I am trying to learn how to add set as contact ringtone feature. I already know how to set default ringtone but I can't figure how to set as contact ringtone.
I got to the part where I choose contact, but I don't know how to assign ringtone to that contact.
That part is bugging me and I can't seem to find answer in questions that were already asked on this topic.
Here is my code so far:
static public final int CONTACT_CHOOSER_ACTIVITY_CODE = 73729;
private File csound;
private final File rpath = new File(Environment.getExternalStorageDirectory() + "/Ringtone sounds/Ringtones");
#Override
public void onClick(View v) {
setContRing();
}
private void setContRing() {
Boolean success = false;
csound = new File(rpath, FNAME);rpath.mkdirs();
if (!csound.exists()) {
try {
InputStream in = getResources().openRawResource(FPATH);
FileOutputStream out = new FileOutputStream(csound.getPath());
byte[] buff = new byte[1024];
int read = 0;
try {
while ((read = in.read(buff)) > 0) {
out.write(buff, 0, read);
}
} finally {
in.close();
out.close();
}
} catch (Exception e) {
success = false;
}
} else {
success = true;
setContRingtone();
}
if (!success) {
setContRingtone();
}
}
private void setContRingtone() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
startActivityForResult(intent, CONTACT_CHOOSER_ACTIVITY_CODE);
}
});
}
Edit for bounty: I am wondering if someone can show me how to do so, I tried with codes found in other questions but I couldn't apply them to my code. I can copy file but how to get contact and assign ringtone to that contact?
From set custom ringtone to specific contact number
Android has a special column for this: ContactsContract.CUSTOM_RINGTONE.
So, you could use ContactsContract.Contacts.getLookupUri to get your contact's Uri, after that pretty much all that's left is to call ContentResolver.update.
Here's an example of looking up a contact by their phone number, then applying a custom ringtone:
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.PhoneLookup;
// The Uri used to look up a contact by phone number
final Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "012-345-6789");
// The columns used for `Contacts.getLookupUri`
final String[] projection = new String[] {
Contacts._ID, Contacts.LOOKUP_KEY
};
// Build your Cursor
final Cursor data = getContentResolver().query(lookupUri, projection, null, null, null);
data.moveToFirst();
try {
// Get the contact lookup Uri
final long contactId = data.getLong(0);
final String lookupKey = data.getString(1);
final Uri contactUri = Contacts.getLookupUri(contactId, lookupKey);
if (contactUri == null) {
// Invalid arguments
return;
}
// Get the path of ringtone you'd like to use
final String storage = Environment.getExternalStorageDirectory().getPath();
final File file = new File(storage + "/AudioRecorder", "hello.mp4");
final String value = Uri.fromFile(file).toString();
// Apply the custom ringtone
final ContentValues values = new ContentValues(1);
values.put(Contacts.CUSTOM_RINGTONE, value);
getContentResolver().update(contactUri, values, null, null);
} finally {
// Don't forget to close your Cursor
data.close();
}
Also, you'll need to add both permissions to read and write contacts:
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
To extend a bit on this, and how to modify it to your need, change phone number 012-345-6789 in this line to the one you are looking for
// The Uri used to look up a contact by phone number
final Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "012-345-6789");
And set your default CUSTOM_RINGTONE in your phone ContactsContract. There is another, similar, option here:
Setting contact custom ringtone, how?
Related
In my app, the user can choose where the created files (text files) are created.
This part is working fine.
But now, I want to open an external "file explorer" app, pointing directly to the chosen folder.
The "file explorer " apps I know accept an absolute path as input (like /storage/emulated/0/Documents/test_folder)
When the user chooses a folder (with Intent.ACTION_OPEN_DOCUMENT_TREE), I get a content uri (like content://com.android.externalstorage.documents/tree/home%3Atest_folder)
Another example with an external sd card:
uri: content://com.android.externalstorage.documents/tree/3877-DB74%3ADocuments%2Ftest_folder
expected path: /storage/3877-DB74/Documents/test_folder
The uri points to a folder, not a file, so I can't use something like openInputStream
I have tried :
File f = new File(uri.getPath());
String path = f.getAbsolutePath();
but it gives: /tree/home:test_folder or /tree/3877-DB74:Documents/test_folder if on sd card
How can I get the real absolute path?
The code I use to call a file explorer:
Intent intent = new Intent(Intent.ACTION_VIEW);
String path = getExternalFilesDir(null).getAbsolutePath();
intent.setDataAndType(Uri.parse(path), "resource/folder");
if (intent.resolveActivityInfo(getPackageManager(), 0) != null)
{
startActivity(intent);
}
so basically you want to get file path from uri
you give try with this code
https://gist.github.com/pratikbutani/eb56f6f9f7013e31d8bfea9effbd4251
I have tried the suggested code (see above).
Unfortunately, I got an exception:
Caused by: java.lang.UnsupportedOperationException: Unsupported Uri content://com.android.externalstorage.documents/tree/home%3Atest_folder
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:167)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:418)
at android.content.ContentResolver.query(ContentResolver.java:760)
at android.content.ContentResolver.query(ContentResolver.java:710)
at android.content.ContentResolver.query(ContentResolver.java:668)
at ....UriUtils.getDataColumn(UriUtils.java:278)
Here is a copy of the code:
private static String getDataColumn(Context context, Uri uri)
{
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection,
null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
I finally wrote my own method to get the absolute path for a folder from a Uri.
It is surely not fully generic, but it meets my need.
if it can help someone, here is my code:
Note: VOLUME_MAP is a map containing all mounted external volumes
/**************************************************************************/
public static String getRealPathFromContentUri(final Uri uri)
{
if (!isExternalStorageDocument(uri))
{
return null;
}
List<String> segs = uri.getPathSegments();
if (!"tree".equalsIgnoreCase(segs.get(0)))
{
return null;
}
String path = uri.getLastPathSegment();
final String[] split = path.split(":");
final String volumeId = split[0];
String userPath = "";
if (split.length > 1)
{
userPath = "/" + split[1];
}
if ("primary".equalsIgnoreCase(volumeId))
{
return Environment.getExternalStorageDirectory().getAbsolutePath() + userPath;
}
if ("home".equalsIgnoreCase(volumeId))
{
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath() + userPath;
}
// look for real volumeId
final String volumeName = VOLUME_MAP.get(volumeId);
if (volumeName == null)
{
return null;
}
path = "/storage";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
{
path = Environment.getStorageDirectory().getAbsolutePath();
}
return path + "/" + volumeId + userPath;
}
Thanks to all contributors on this topic.
The app sends the user to SAF picker with ACTION_OPEN_DOCUMENT_TREE:
void openStoragePicker() {
String messageTitle = "Choose directory app to use";
Intent intent = new Intent(ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(Intent.createChooser(intent, messageTitle), Dry.REQUEST_CHOOSE_APP_DIR);
}
In onActivityResult, we take persistable permission and store a String of the Uri:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
switch (resultCode) {
case Activity.RESULT_OK:
if (requestCode == Dry.REQUEST_CHOOSE_APP_DIR) {
if (resultData == null) {
Log.d(Dry.TAG, "result data null");
} else {
if (resultData.getData() != null) {
Uri uri = resultData.getData();
Storage.releasePersistedPermissions(this);
getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Storage.setSharedPrefString(uri.toString(), Storage.SHARED_PREF_APP_DIR_URI, this);
dbw.clearAlreadyPlayed();
}
}
}
break;
case Activity.RESULT_CANCELED:
//
break;
}
}
We recreate the tree Uri when we need it:
static Uri getTheDir(Context context) {
String result = Storage.getSharedPrefString(SHARED_PREF_APP_DIR_URI, context);
if (result == DEFAULT_SHARED_PREF_STRING) {
return null;
}
Uri dirUriParsed = Uri.parse(Uri.decode(result));
Log.d(Dry.TAG, "the dir uri parsed: " + dirUriParsed.toPath());
return dirUriParsed;
}
We want to list the files, and we can, using the pattern shown here.
static ArrayList<String> getFiles(Context context) {
ArrayList<String> fileStrings = new ArrayList<>();
Uri rootUri = getTheDir(context);
if (rootUri == null) {
return fileStrings;
}
long startTime = System.currentTimeMillis();
ContentResolver contentResolver = context.getContentResolver();
String theDocToReturnChildrenFor = DocumentsContract.getTreeDocumentId(rootUri);
Log.d(Dry.TAG, "theDocToReturnChildrenFor: " + theDocToReturnChildrenFor);
Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, theDocToReturnChildrenFor);
List<Uri> dirNodes = new LinkedList<>();
dirNodes.add(childrenUri);
while(!dirNodes.isEmpty()) {
childrenUri = dirNodes.remove(0);
Cursor c = contentResolver.query(childrenUri, new String[]{DocumentsContract.Document.COLUMN_DOCUMENT_ID, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_MIME_TYPE}, null, null, null);
try {
while (c.moveToNext()) {
final String docId = c.getString(0);
final String name = c.getString(1);
final String mime = c.getString(2);
if (isDirectory(mime)) {
if (Arrays.asList(SUBDIRECTORIES_TO_OMIT).contains(name)) {
continue;
}
final Uri newNode = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, docId);
dirNodes.add(newNode);
} else {
for (String ext: SUPPORTED_FILE_EXTENSIONS) {
if (name.endsWith(ext)) {
fileStrings.add(docId);
break;
}
}
}
}
} finally {
closeQuietly(c);
}
}
Log.d(Dry.TAG, "fileStrings length: " + fileStrings.size() + "time spent building song list: " + ((System.currentTimeMillis() - startTime) / 1000.0) + "s");
return fileStrings;
}
But, this only works as expected when the directory happens to be a top-level directory within the storage volume. If the directory that the user chose is not a direct child of the volume root, then, when we try DocumentsContract.getTreeDocumentId(rootUri), it returns not the document ID for that URI, but rather the document ID for its highest parent before the volume root!
The log call that prints the reconstructed Uri gives this output:
the dir uri parsed: /tree/primary:a test dir/a child test dir/3rd level dir
But the other log call that prints the doc ID prints this:
theDocToReturnChildrenFor: primary:a test dir
Am I doing it wong? Is this an Android bug? I noticed this question describes the exact same behavior from this method. That issue was solvable by following the established recursive listing pattern, but, that user says:
It is almost like getTreeDocumentId(rootUri) is returning what getRootId(rootUri) should be returning.
The docs for this method are not helpful, they are brief and have a typo, leaving the meaning unclear. DocumentsContract.getTreeDocumentId docs.
Target SDK of the app is 30. The device Android version is also api 30 (Android 11).
If someone could help me to get the correct doc ID for the user-selected directory, I would appreciate it.
Uri dirUriParsed = Uri.parse(Uri.decode(result))
Try:
Uri dirUriParsed = Uri.parse(result)
Some of my users have reported to Google Play the following error when trying to select a ringtone in my app. (there's more to it, but it's not relevant)
java.lang.SecurityException: Permission Denial:
reading com.android.providers.media.MediaProvider
uri content://media/external/audio/media
from pid=5738, uid=10122 requires android.permission.READ_EXTERNAL_STORAGE
I assume this issue is happening due to certain tones that are on external storage. I don't want to include the READ_EXTERNAL_STORAGE permission in my app unless I absolutely have to.
Is there a way to circumvent the issue and just exclude any tones that may be on the external storage?
Note: I'm getting ringtones with RingtoneManager and convert them between String and Uri. No other code is touching the user's media.
Also, I do not have a line number since the stacktrace is from obfuscated code and re-mapping the stack trace did not provide line number.
Just had the same problem and came up with the following solution:
private Cursor createCursor()
{
Uri uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
String[] columns = new String[]
{
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.TITLE_KEY
};
String filter = createBooleanFilter(MediaStore.Audio.AudioColumns.IS_ALARM);
String order = MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
return getContext().getContentResolver().query(uri, columns, filter, null, order);
}
private String createBooleanFilter(String... columns)
{
if(columns.length > 0)
{
StringBuilder sb = new StringBuilder();
sb.append("(");
for(int i = columns.length - 1; i > 0; i--)
{
sb.append(columns[i]).append("=1 or ");
}
sb.append(columns[0]);
sb.append(")");
return sb.toString();
}
return null;
}
To get the Uri of a ringtone you need to combine the INTERNAL_CONTENT_URI with the _ID column value, you can do this by using ContentUris class:
Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, cursor.getLong(0));
You can find the external storage directory without needing WRITE_EXTERNAL_STORAGE or READ_EXTERNAL_STORAGE by using Environment.getExternalStorageDirectory().
You can then compare the paths for the URIs provided by RingtoneManager to this path to see if they are on the external storage or not and if so add those items to a List.
Then, rather than passing the raw Cursor to the UI you can use that List with a ListAdapter instead.
For example (untested, you may need to change the method of comparing paths):
class RingtoneDetails
{
public String ID;
public String Title;
public Uri Uri;
public RingtoneDetails(String id, String title, Uri uri)
{
ID = id;
Title = title;
Uri = uri;
}
}
private List<RingtoneDetails> getNonExternalRingtones(RingtoneManager manager)
{
List<RingtoneDetails> ringtones = new List<RingtoneDetails>();
Cursor cursor = manager.getCursor();
String extDir = Environment.getExternalStorageDirectory().getAbsolutePath();
while (cursor.moveToNext())
{
String id = cursor.getString(cursor.getColumnIndex(RingtoneManager.ID_COLUMN_INDEX));
String title = cursor.getString(cursor.getColumnIndex(RingtoneManager.TITLE_COLUMN_INDEX));
Uri uri= cursor.getString(cursor.getColumnIndex(RingtoneManager.URI_COLUMN_INDEX));
if(!uri.getPath().contains(extDir))
{
ringtones.add(new Ringtone(id, title, uri));
}
}
return ringtones;
}
Previously, I was using RingtoneManager to get a list and display that in a dialog for a user to select. It was throwing the SecurityException on ringtoneManager.getCursor();
I did not want to add the external storage permission, so I switched to doing:
final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Select Ringtone");
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE,RingtoneManager.TYPE_ALL);
startActivityForResult( intent, RINGTONE_RESULT);
And then in onActivityResult
if (requestCode == RINGTONE_RESULT&&resultCode == RESULT_OK&&data!=null) {
try {
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (uri==null){
setSilent(); //UI stuff in this method
} else {
Ringtone ringtone = RingtoneManager.getRingtone(context, uri);
String name = ringtone.getTitle(context);
changeTone.setText(name); //changeTone is a button
}
} catch (SecurityException e){
setSilent();
Toast.makeText(context, "Error. Tone on user storage. Select a different ringtone.", Toast.LENGTH_LONG).show();
} catch (Exception e){
setSilent();
Toast.makeText(context, "Unknown error. Select a different ringtone.", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(context, "Ringtone not selected. Tone set to silent.", Toast.LENGTH_SHORT).show();
setSilent();
}
Question: how to make the media store to refresh its entry of a DELETED file?
After deleting a photo in code from the external storage, I still see a slot for the deleted photo in the gallery - blank photo.
It seems that the gallery reflects the media store and the deleted photo is found in the media store until the phone is restarted or generally - until the media is rescanned.
Trying to scan the deleted file did not help scanning deleted files (works just for new or existing files): MediaScannerConnection.scanFile(Application.get(), new String[]{file.getPath()}, null, null) (I tried scanning the parent folder as well).
Also tried ACTION_MEDIA_SCANNER_SCAN_FILE to no avail. Example: Application.get().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)))
Sending a broadcast receiver to rescan the entire external storage (thus refreshing the media store)did the trick: Application.get().sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(Environment.getExternalStorageDirectory())))
BUT, it seems that Android, as of 4.4, throws a security exception when trying to manually send the ACTION_MEDIA_MOUNTED system broadcast. See #CommonsWare's post: http://commonsware.com/blog/2013/11/06/android-4p4-permission-regressions.html
So, I'm stuck with no solution for refreshing the media store upon file(/photo/video/etc.) deletion.
I found the following that works for me in 4.4 on a Nexus 10.
// request scan
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, SELECT_PICTURE);
Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
scanIntent.setData(Uri.fromFile(refreshFile));
sendBroadcast(scanIntent);
"refreshFile" is the file I deleted that I get from my String "fPath" and then convert it to a file.
String filePath = fPath;
File refreshFile = new File(filePath);
I had the same issue. I wrote the following code and it worked on all versions from lollipop to oreo. I also called the mediastore.scanfile() method to ensure that MediaStore is updated. Adding the code below - you might not want to use the "delete()" method in future as the scanfile() might be comprehensive. But, if you want to support older phones then delete() would probably be safer.
// fileID == MediaStore.Images.Media._ID; for the file when you get the file from the content
// resolver
public static boolean deleteCREntryForFilePath(Context context, String filePath, long fileID) {
boolean fDeleted = false;
ContentResolver cr = context.getContentResolver();
int rowsDeleted = 0;
Uri imageURI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String deleteStr = MediaStore.Images.Media._ID + "=" + fileID;
MediaScannerConnection.scanFile(context, new String[]{filePath}, null, null);
// Remove entry from database
rowsDeleted = context.getContentResolver().delete(
imageURI, deleteStr, null);
if (rowsDeleted > 0)
fDeleted = true;
return(fDeleted);
}
Here is the code to get the file-id (name of the function is getfileId()) . It works for different file-types. You cannot compile the code as it is because it uses an internal object-type but you should be easily able to convert this for generic use.
public static String[] getCombinedEntityColumns(Constants.DELASHARE_OBJECT_TYPES objType) {
String[] entityColumns = new String[5];
switch (objType) {
case DELASHARE_OBJECT_PICTURE:
case DELASHARE_OBJECT_MUSIC:
case DELASHARE_OBJECT_VIDEO: {
entityColumns[0] = MediaStore.Images.Media.DISPLAY_NAME;
entityColumns[1] = MediaStore.Images.Media.DATA;
entityColumns[2] = MediaStore.Images.Media._ID;
entityColumns[3] = MediaStore.Images.Media.DATE_ADDED;
//entityColumns[3] = MediaStore.Images.Media.DATE_TAKEN;
entityColumns[4] = MediaStore.Images.Media.SIZE;
break;
}
case DELASHARE_OBJECT_APK:
case DELASHARE_OBJECT_DOCUMENT:
case DELASHARE_OBJECT_DOWNLOAD:
case DELASHARE_OBJECT_SEARCH_RESULTS:
default: {
entityColumns[0] = MediaStore.Files.FileColumns.DISPLAY_NAME;
entityColumns[1] = MediaStore.Files.FileColumns.DATA;
entityColumns[2] = MediaStore.Files.FileColumns._ID;
entityColumns[3] = MediaStore.Files.FileColumns.DATE_MODIFIED;
entityColumns[4] = MediaStore.Files.FileColumns.SIZE;
break;
}
}
return (entityColumns);
}
public static Uri getCategoryUri(Constants.DELASHARE_OBJECT_TYPES categoryObjType) {
Uri objUri = null;
switch(categoryObjType) {
case DELASHARE_OBJECT_PICTURE:
objUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
break;
case DELASHARE_OBJECT_VIDEO:
objUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
break;
case DELASHARE_OBJECT_MUSIC:
objUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
break;
case DELASHARE_OBJECT_DOWNLOAD: {
File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
objUri = Uri.fromFile( downloadDir);
//objUri = MediaStore.Files.getContentUri("external");
break;
}
case DELASHARE_OBJECT_APK:
case DELASHARE_OBJECT_DOCUMENT:
case DELASHARE_OBJECT_SEARCH_RESULTS:
default:
objUri = MediaStore.Files.getContentUri("external");
break;
}
return(objUri);
}
public static long getFileId(Context context, String dirPath, String filePath, String fileName, Constants.DELASHARE_OBJECT_TYPES objType) {
boolean fIDFound = false;
long id = 0;
if (!fIDFound) {
String sortOrder = null;
String[] entityColumns = getCombinedEntityColumns(objType);
Uri categoryUri = getCategoryUri(objType);
String selection = null;
String[] selectionArgs = new String[]{Constants.DELA_PERCENT_STR + dirPath};
ContentResolver cr = context.getContentResolver();
Cursor cursor = null;
switch (objType) {
case DELASHARE_OBJECT_PICTURE:
selection = MediaStore.Images.Media.DATA + " LIKE ?";
break;
case DELASHARE_OBJECT_VIDEO:
selection = MediaStore.Video.Media.DATA + " LIKE ?";
break;
case DELASHARE_OBJECT_DOCUMENT:
default:
selection = MediaStore.Files.FileColumns.DATA + " LIKE ?";
break;
}
cursor = cr.query(
categoryUri,
entityColumns,
selection,
selectionArgs,
sortOrder);
if (cursor != null && cursor.moveToFirst()) {
id = cursor.getLong(cursor.getColumnIndex(entityColumns[2]));
if (id != 0) {
fIDFound = true;
}
}
if (cursor != null) {
cursor.close();
cursor = null;
}
}
return(id);
}
I had the same question as you now that the sendBroadcast approach is disallowed in 4.4 and found a good solution here using the Media Store content provider: https://stackoverflow.com/a/20780472/1060805
I tested it out on Android 4.4 and it works nicely. I think it is a solid approach.
Try
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
Add this to your manifest:
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<data android:scheme="file" />
</intent-filter>
I have registered my app to receive files (of any type, not just images) from other apps following this post.
I have implemented the solution that was answered but I cannot find a way to retrieve the "file name" of the data stream.
As an example from an Uri like:
content://downloads/all_downloads/5
I can get the stream out but I don't know anything about the name of the original file generating it.
Is there a way to retrieve it?
In MOST cases this will solve your problem:
Uri intentData = intent.getData();
if (intentData != null) {
String filePath;
if("content".equals(intent.getScheme()))
{
filePath = getFilePathFromContentUri(intentData);
}
else
{
filePath = intentData.getPath();
}
}
private String getFilePathFromContentUri(Uri selectedUri) {
String filePath;
String[] filePathColumn = {MediaColumns.DATA};
Cursor cursor = getContentResolver().query(selectedUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
}
Is there a way to retrieve it?
Generally, no, because there may not be a name, in part because there may not be a file. You may be able to get an InputStream on the contents, but that does not mean that there is a file behind the InputStream.
There may be some specific hacks for some specific providers (e.g., MediaStore) to try to determine the file name associated with some data Uri, though such hacks may not be reliable.
onCreate()
Intent intent1 = getIntent();
String action = intent1.getAction();
String type = intent1.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
this.handleSend(intent1);
}
void handleSend(Intent intent) {
try {
Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
imageShare.setImageURI(imageUri);
} catch (Exception e) {
e.printStackTrace();
}
}