I'm making a profile photo change function using Retrofit in android pie.
So I succeeded in uploading the photos taken with the camera to the server. But I don't know how to transfer the photos selected from the gallery to my server. (I'm fine with any kind of code in Java Kotlin.)
I will upload the video later.
I searched a lot on Google, but it was hard to get the information I wanted.
Well done in the google doc but i don't know how to do it. https://developer.android.com/guide/topics/providers/document-provider
The Google doc shows examples of using bitmap or inputstream or something.
Do I need a bitmap or inputstream to upload photos using Retrofit?
I actually need a valid uri.
public void performFileSearch() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, PICTURES_DIR_ACCESS_REQUEST_CODE);
}
@Override
public void onActivityResult(int requestCode, int resultCode,Intent resultData) {
if (requestCode == READ_REQUEST_CODE && resultCode ==Activity.RESULT_OK) {
Uri uri = null;
if (resultData != null) {
uri = resultData.getData();
Log.i(TAG, "Uri: " + uri.toString());
showImage(uri);
}
}
}
public void Edit_Profile (String Image_Uri) {
File file = new File(Image_Uri);
RequestBody requestBody = RequestBody.create(file, MediaType.parse("image/*"));
MultipartBody.Part body = MultipartBody.Part.createFormData("uploaded_file", Num+ID+".jpg", requestBody);
}
In fact, onActivityResult returns the following type of uri.
content://com.android.providers.media.documents/document/image%3A191474
So when I try to send it to my server using that uri I get a FileNotFoundException error.
Using putExtra() and getExtras() in android Intents are asynchronous messages which allow Android components to request functionality from other components of the Android system. For example an Activity can send an Intents to the Android system which starts another Activity .
An intent allows you to start an activity in another app by describing a simple action you'd like to perform (such as "view a map" or "take a picture") in an Intent object.
This is a privacy restriction introduced in Android-Q. Direct access to shared/external storage devices is deprecated when an app targets API 29 and the path returned from getExternalStorageDirectory method is no longer directly accessible to apps. Use the app-specific directory to write & read files.
By default, apps targeting Android 10 and higher are given scoped access into external storage, or scoped storage. Such apps can see the following types of files within an external storage device without needing to request any storage-related user permissions:
Files in the app-specific directory, accessed using getExternalFilesDir(). Photos, videos, and audio clips that the app created from the media store.
Go through the documentation Open files using storage access framework
Coming to the context, One thing that you can do is that as CommonsWare suggested use
InputStreamRequestBody
. Otherwise, copy the selected file to your app sandbox folder IE, app-specific directory, then access the file from there without any permission. Just see the below implementation that works in Android-Q and later.
Perform file search
private void performFileSearch(String messageTitle) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
intent.setType("application/*");
String[] mimeTypes = new String[]{"application/x-binary,application/octet-stream"};
if (mimeTypes.length > 0) {
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
}
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(Intent.createChooser(intent, messageTitle), OPEN_DIRECTORY_REQUEST_CODE);
} else {
Log.d("Unable to resolve Intent.ACTION_OPEN_DOCUMENT {}");
}
}
onActivityResult returned
@Override
public void onActivityResult(int requestCode, int resultCode, final Intent resultData) {
// The ACTION_OPEN_DOCUMENT intent was sent with the request code OPEN_DIRECTORY_REQUEST_CODE.
// If the request code seen here doesn't match, it's the response to some other intent,
// and the below code shouldn't run at all.
if (requestCode == OPEN_DIRECTORY_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
// The document selected by the user won't be returned in the intent.
// Instead, a URI to that document will be contained in the return intent
// provided to this method as a parameter. Pull that uri using "resultData.getData()"
if (resultData != null && resultData.getData() != null) {
new CopyFileToAppDirTask().execute(resultData.getData());
} else {
Log.d("File uri not found {}");
}
} else {
Log.d("User cancelled file browsing {}");
}
}
}
File writing to app specific path
public static final String FILE_BROWSER_CACHE_DIR = "CertCache";
@SuppressLint("StaticFieldLeak")
private class CopyFileToAppDirTask extends AsyncTask<Uri, Void, String> {
private ProgressDialog mProgressDialog;
private CopyFileToAppDirTask() {
mProgressDialog = new ProgressDialog(YourActivity.this);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog.setMessage("Please Wait..");
mProgressDialog.show();
}
protected String doInBackground(Uri... uris) {
try {
return writeFileContent(uris[0]);
} catch (IOException e) {
Log.d("Failed to copy file {}" + e.getMessage());
return null;
}
}
protected void onPostExecute(String cachedFilePath) {
mProgressDialog.dismiss();
if (cachedFilePath != null) {
Log.d("Cached file path {}" + cachedFilePath);
} else {
Log.d("Writing failed {}");
}
}
}
private String writeFileContent(final Uri uri) throws IOException {
InputStream selectedFileInputStream =
getContentResolver().openInputStream(uri);
if (selectedFileInputStream != null) {
final File certCacheDir = new File(getExternalFilesDir(null), FILE_BROWSER_CACHE_DIR);
boolean isCertCacheDirExists = certCacheDir.exists();
if (!isCertCacheDirExists) {
isCertCacheDirExists = certCacheDir.mkdirs();
}
if (isCertCacheDirExists) {
String filePath = certCacheDir.getAbsolutePath() + "/" + getFileDisplayName(uri);
OutputStream selectedFileOutPutStream = new FileOutputStream(filePath);
byte[] buffer = new byte[1024];
int length;
while ((length = selectedFileInputStream.read(buffer)) > 0) {
selectedFileOutPutStream.write(buffer, 0, length);
}
selectedFileOutPutStream.flush();
selectedFileOutPutStream.close();
return filePath;
}
selectedFileInputStream.close();
}
return null;
}
// Returns file display name.
@Nullable
private String getFileDisplayName(final Uri uri) {
String displayName = null;
try (Cursor cursor = getContentResolver()
.query(uri, null, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
displayName = cursor.getString(
cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
Log.i("Display Name {}" + displayName);
}
}
return displayName;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With