1

AWS SDK requires a File object for uploading data to a bucket. I'm having trouble creating a File object required by transferUtility.upload. I know new File(selectedImageUri.getPath()) does not work. I've tried reading about how to make a file from a uri, but there doesn't seem to be an easy way of doing that. Should I be using something other than TransferUtility?

public class SettingsActivity extends AppCompatActivity {
    ...

    private class ChangeSettingsTask extends AsyncTask<Void, Void, Boolean> {

    public void uploadData(File image) {
        TransferUtility transferUtility =
                TransferUtility.builder()
                        .defaultBucket("some-bucket")
                        .context(getApplicationContext())
                        .s3Client(new AmazonS3Client( new BasicAWSCredentials( "something", "something") ))
                        .build();

        TransferObserver uploadObserver =
                transferUtility.upload("somefile.jpg", image);

        ...
    }

    @Override
    protected void onActivityResult(int reqCode, int resultCode, Intent data) {
        super.onActivityResult(reqCode, resultCode, data);

        if (resultCode == RESULT_OK) {
            Uri selectedImageUri = data.getData();
            uploadData(new File(selectedImageUri.getPath()));
        }
    }
}
Michael Blake
  • 993
  • 1
  • 8
  • 18
  • "I've tried reading about how to make a file from a uri, but there doesn't seem to be an easy way of doing that" -- call `getContentResolver()` on a `Context` to get a `ContentResolver`. Call `openInputStream()` on the `ContentResolver`, passing in the `Uri`, to get an `InputStream`. Open a `FileOutputStream` on some file that you control. Copy the bytes from the `InputStream` to the `OutputStream`. Done. Or, grab [my CWAC-Document library](https://github.com/commonsguy/cwac-document) and use `DocumentFileCompat` and `copyTo()` to do the copying for you. – CommonsWare Feb 11 '18 at 11:48
  • @CommonsWare So if I understand what this is doing, it's copying the contents of the photo to upload to another file, then using that, correct? – Michael Blake Feb 11 '18 at 20:50
  • It is copying the contents to a file. Whether it is "another file" depends on whether it was a file in the first place. [Do not assume that a `Uri` necessarily points to an accessible file on the filesystem](https://stackoverflow.com/a/35870955/115145). – CommonsWare Feb 11 '18 at 21:07

2 Answers2

2

You can use this function from the S3TransferUtilitySample App to get the file path for the URI.

    private String getPath(Uri uri) throws URISyntaxException {
        final boolean needToCheckUri = Build.VERSION.SDK_INT >= 19;
        String selection = null;
        String[] selectionArgs = null;
        // Uri is different in versions after KITKAT (Android 4.4), we need to
        // deal with different Uris.
        if (needToCheckUri && DocumentsContract.isDocumentUri(getApplicationContext(), uri)) {
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            } else if (isDownloadsDocument(uri)) {
                final String id = DocumentsContract.getDocumentId(uri);
                uri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
            } else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                if ("image".equals(type)) {
                    uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }
                selection = "_id=?";
                selectionArgs = new String[] {
                        split[1]
                };
            }
        }
        if ("content".equalsIgnoreCase(uri.getScheme())) {
            String[] projection = {
                    MediaStore.Images.Media.DATA
            };
            Cursor cursor = null;
            try {
                cursor = getContentResolver()
                        .query(uri, projection, selection, selectionArgs, null);
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                if (cursor.moveToFirst()) {
                    return cursor.getString(column_index);
                }
            } catch (Exception e) {
            }
        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }
        return null;
    }

Now, when you have the filePath, you can construct the file object from it.

File file = new File(filePath);
TransferObserver observer = transferUtility.upload(Constants.BUCKET_NAME, file.getName(),
file);

For further information, you can try out the sample: https://github.com/awslabs/aws-sdk-android-samples/tree/master/S3TransferUtilitySample

Karthikeyan
  • 1,411
  • 1
  • 13
  • 13
  • Thank you very much, I've been facing this problem for days, the issue was solved by this getPath() method. – fullmoon Jul 04 '19 at 06:15
2

You may use it like this

Below code is used to access your aws s3 in which you have to pass accessKey and secretKey as your credentials.

BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey,secret);
AmazonS3Client s3 = new AmazonS3Client(credentials);
s3.setRegion(Region.getRegion(Regions.US_EAST_1));

Transfer utility is the Class from which you can upload your file to s3.

TransferUtility transferUtility = new TransferUtility(s3, UploadFileActivity.this);

Get the path of your file from your storage and pass it as a file as below

        //You have to pass your file path here.
        File file = new File(filePath);
        if(!file.exists()) {
            Toast.makeText(UploadFileActivity.this, "File Not Found!", Toast.LENGTH_SHORT).show();
            return;
        }
        TransferObserver observer = transferUtility.upload(
                Config.BUCKETNAME,
                "video_test.jpg",
                file
        );

Here you can use observer.setTransferListener to know the progress of your uploading file

observer.setTransferListener(new TransferListener() {
            @Override
            public void onStateChanged(int id, TransferState state) {

                if (state.COMPLETED.equals(observer.getState())) {

                    Toast.makeText(UploadFilesActivity.this, "File Upload Complete", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {

            }

            @Override
            public void onError(int id, Exception ex) {

                Toast.makeText(UploadFilesActivity.this, "" + ex.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
Sagar A
  • 89
  • 7