Whether exists way to get direct path to some ringtone uri,which we can get via ringtoneManager,which will works for all apis. I need in direct file path to play it on media player without looping. Have anybody ideas,how to get absolute path of any ringtone? Thanks everybody for any help.
I was struggling with this issue as well, And i found solution that i explain you how i get atual ringtone in Android.
NOTE: but you need those permission first.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Uri defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(getActivity().getApplicationContext(), RingtoneManager.TYPE_RINGTONE);
Ringtone defaultRingtone = RingtoneManager.getRingtone(getActivity(), defaultRingtoneUri);
OR
You need to got all default ringtones in android with path. then you can use this code in android.
RingtoneManager ringtoneManager = new RingtoneManager(this);
ringtoneManager.setType(RingtoneManager.TYPE_RINGTONE);
Cursor cursor = ringtoneManager.getCursor();
while (cursor.moveToNext()) {
Log.e("RINGTONE", "NAME: " + cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX));
Log.e("RINGTONE", "PATH: " + cursor.getString(RingtoneManager.URI_COLUMN_INDEX));
}
Related
I'm unable to create directory in android 10. It's working on devices till android Oreo.
I tried two ways for creating folders.
Using File.mkdir():
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
if (!f.isFile()) {
if (!(f.isDirectory())) {
success = f.mkdir();
}
Here, the variable success is always false which means the directory isn't created.
Using Files.createDirectory():
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
if (!f.isFile()) {
if (!(f.isDirectory())) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
Files.createDirectory(Paths.get(f.getAbsolutePath()));
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), R.string.unable_to_download, Toast.LENGTH_LONG).show();
}
} else {
f.mkdir();
}
}
which causes this exception:
pzy64.pastebinpro W/System.err: java.nio.file.AccessDeniedException: /storage/emulated/0/Pastebin
pzy64.pastebinpro W/System.err: at sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:391)
pzy64.pastebinpro W/System.err: at java.nio.file.Files.createDirectory(Files.java:674)
I've implemented the run-time permissions and
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
are all set.
As was first disclosed back in March 2019, you no longer have access by default to arbitrary locations on external storage or removable storage on Android 10+. This includes Environment.getExternalStorageDirectory() and other methods on Environment (e.g., getExternalStoragePublicDirectory().
For Android 10 and 11, you can add android:requestLegacyExternalStorage="true" to your <application> element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work.
Otherwise, your choices are:
Use methods on Context, such as getExternalFilesDir(), to get at directories on external storage into which your app can write. You do not need any permissions to use those directories on Android 4.4+. However, the data that you store there gets removed when your app is uninstalled.
Use the Storage Access Framework, such as ACTION_OPEN_DOCUMENT and ACTION_CREATE_DOCUMENT.
If your content is media, you can use MediaStore to place the media in standard media locations.
For Android 10, you can add
android:requestLegacyExternalStorage="true"
to your element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work. This fix will not work on Android R and higher though, so this is only a short-term fix.
There are more restrictions in Android API 30
you can only write in your app-specific files
File dir_ = new File(context.getFilesDir(), "YOUR_DIR");
dir_.mkdirs();
or in the external storage of your app Android/data
File dir_ = new File(myContext.getExternalFilesDir("FolderName"),"YOUR_DIR");
UPDATE
this answer provided another solution https://stackoverflow.com/a/65744517/8195076
UPDATE
another way is to grant this permission in manifest
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
like this answer https://stackoverflow.com/a/66968986/8195076
This works for me and I think it's functional on Android 10>
ContentResolver resolver = getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Folder Example");
String path = String.valueOf(resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues));
File folder = new File(path);
boolean isCreada = folder.exists();
if(!isCreada) {
folder.mkdirs();
}
You can use public directory to save files in Android 11 like this:
dir = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS).getPath()
+ "/foldername");
if (!dir.exists()) {
dir.mkdir();
Toast.makeText(getApplicationContext(), "not exist", Toast.LENGTH_SHORT).show();
}
Since Q beta 4 it's possible to opt-out of that feature by:
targeting api 28 (or lower)
using requestLegacyExternalStorage manifest attribute:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
only use
android:requestLegacyExternalStorage="true"
in manifests
So this functionality was working previously, but I guess somewhere when I upgraded versions, it does not anymore.
I want to create dynamically an audio file (this is working), and copy it to the storage (this is working, it is currently copied to my local app storage :
Android/data/com.mypackagename/files/xxx.mp3
Then I create a new ContentValues with the data & metadata and insert it into MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.
After that I set ringtone and launch ringtone picker to check:
RingtoneManager.setActualDefaultRingtoneUri(_instance, RingtoneManager.TYPE_RINGTONE, newUri);
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, newUri);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, newUri);
startActivityForResult(intent, 1);
But the ringtone set is only the ID of the media, not the name, and I can't find it in the list..
I though the Media wasn't scanned, so i tried this beforehand:
Intent scanFileIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri);
sendBroadcast(scanFileIntent);
I'm not really sure what this does, but it didn't helped.
Any clues what's going on with the current status of creating ringtone with Android Studio ?
So here was my error. I needed to correct some things in my Manifest to get the rights permissions:
//Without this folders will be inaccessible in Android-11 and above devices
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
//Without this entry storage-permission entry will not be visible under app-info permissions list Android-10 and below
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
tools:ignore="ScopedStorage"/>
//Without this entry the folders will remain in-accessible in Android-10, even if WRITE_EXTERNAL_STORAGE as above is present.
<application
android:requestLegacyExternalStorage="true"/>
The Ringtones external root folder is not accessible from basic WRITE_EXTERNAL_STORAGE permissions anymore. We have access to app specific external folder, & others (link).
Even the Media store does not give you access to this folder, so from Android 11 & forward, you need the MANAGE_EXTERNAL_STORAGE permission, that gives you this warning:
Most apps are not allowed to use MANAGE_EXTERNAL_STORAGE. Because you need to ask for this permission to the user, and he might refuse..
But if you want to do what I wanted to do, you'll need it..
Be sure that your app ask for the permission through:
// permission: Manifest.permission.WRITE_EXTERNAL_STORAGE
// permission_id: 1
public Boolean checkPermission(String permission, Integer permission_id) {
if (ContextCompat.checkSelfPermission(_instance, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(_instance, new String[]{permission}, permission_id);
return false;
} else {
return true;
}
}
I'm unable to create directory in android 10. It's working on devices till android Oreo.
I tried two ways for creating folders.
Using File.mkdir():
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
if (!f.isFile()) {
if (!(f.isDirectory())) {
success = f.mkdir();
}
Here, the variable success is always false which means the directory isn't created.
Using Files.createDirectory():
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
if (!f.isFile()) {
if (!(f.isDirectory())) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
Files.createDirectory(Paths.get(f.getAbsolutePath()));
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), R.string.unable_to_download, Toast.LENGTH_LONG).show();
}
} else {
f.mkdir();
}
}
which causes this exception:
pzy64.pastebinpro W/System.err: java.nio.file.AccessDeniedException: /storage/emulated/0/Pastebin
pzy64.pastebinpro W/System.err: at sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:391)
pzy64.pastebinpro W/System.err: at java.nio.file.Files.createDirectory(Files.java:674)
I've implemented the run-time permissions and
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
are all set.
As was first disclosed back in March 2019, you no longer have access by default to arbitrary locations on external storage or removable storage on Android 10+. This includes Environment.getExternalStorageDirectory() and other methods on Environment (e.g., getExternalStoragePublicDirectory().
For Android 10 and 11, you can add android:requestLegacyExternalStorage="true" to your <application> element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work.
Otherwise, your choices are:
Use methods on Context, such as getExternalFilesDir(), to get at directories on external storage into which your app can write. You do not need any permissions to use those directories on Android 4.4+. However, the data that you store there gets removed when your app is uninstalled.
Use the Storage Access Framework, such as ACTION_OPEN_DOCUMENT and ACTION_CREATE_DOCUMENT.
If your content is media, you can use MediaStore to place the media in standard media locations.
For Android 10, you can add
android:requestLegacyExternalStorage="true"
to your element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work. This fix will not work on Android R and higher though, so this is only a short-term fix.
There are more restrictions in Android API 30
you can only write in your app-specific files
File dir_ = new File(context.getFilesDir(), "YOUR_DIR");
dir_.mkdirs();
or in the external storage of your app Android/data
File dir_ = new File(myContext.getExternalFilesDir("FolderName"),"YOUR_DIR");
UPDATE
this answer provided another solution https://stackoverflow.com/a/65744517/8195076
UPDATE
another way is to grant this permission in manifest
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
like this answer https://stackoverflow.com/a/66968986/8195076
This works for me and I think it's functional on Android 10>
ContentResolver resolver = getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Folder Example");
String path = String.valueOf(resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues));
File folder = new File(path);
boolean isCreada = folder.exists();
if(!isCreada) {
folder.mkdirs();
}
You can use public directory to save files in Android 11 like this:
dir = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS).getPath()
+ "/foldername");
if (!dir.exists()) {
dir.mkdir();
Toast.makeText(getApplicationContext(), "not exist", Toast.LENGTH_SHORT).show();
}
Since Q beta 4 it's possible to opt-out of that feature by:
targeting api 28 (or lower)
using requestLegacyExternalStorage manifest attribute:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
only use
android:requestLegacyExternalStorage="true"
in manifests
My Android app has to launch gmaps on Wear OS
Uri gmmIntentUri = Uri.parse("https://www.google.com/maps/search/?api=1&query=" +Uri.encode( string));
Intent mapIntent = new Intent(ACTION_VIEW, gmmIntentUri);
// mapIntent.setPackage("com.google.android.apps.maps");
if (mapIntent.resolveActivity(activity.getPackageManager()) != null) {
activity.startActivity(mapIntent);
}
but I get an error that says Permission denial... It wants
com.google.android.wearable.READ_SETTINGS
If I put this
<uses-permission android:name="com.google.android.wearable.READ_SETTINGS" />
in the manifest then I get the same kind of error.
I am not able to ask for permission programmatically with something similar to this
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_SETTINGS)
== PackageManager.PERMISSION_GRANTED) {
Log.d("permissions","granted");
} else {
// Show rationale and request permission.
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.READ_SETTINGS},
MY_LOCATION_REQUEST_CODE);
}
because that constant is not found. It is not useful to write the complete com.google.android.wearable.READ_SETTINGS string.
I do not understand why READ_SETTINGS is needed.
How to solve?
Google Maps on wearOS cannot handle Uri.parse("https://www.google.com/maps/search/?api=1&query=" +Uri.encode( string)) or in this format as suggested in documentation Uri gmmIntentUri = Uri.parse("geo:0,0?q=1600 Amphitheatre Parkway, Mountain+View, California"). While the same intent on phone launches Google Maps and shows you a list of suggestions.
My guess is that the Maps app on wearOS is meant to be lightweight , you can only search for something in a particular city or region like this:
// Searches for 'Main Street' near San Francisco
Uri gmmIntentUri = Uri.parse("geo:37.7749,-122.4194?q=101+main+street");
The below link shows examples of Google Maps intents to use on Android : https://developers.google.com/maps/documentation/urls/android-intents
For the error:
com.google.android.wearable.READ_SETTINGS
You don't need to add this in permissions, but check whether your wear app manifest has this :
<uses-feature android:name="android.hardware.type.watch" />
Because I want to make sure the MediaStore has the latest information without having to reboot I'd like to trigger the MediaScanner using the popular way I found on SO
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
This works fine on my Samsung S2 w/ICS but not on my Nexus 7 w/JellyBean. Logcat shows this on my Nexus 7:
WARN/ActivityManager(480): Permission denied: checkComponentPermission() owningUid=10014
WARN/BroadcastQueue(480): Permission Denial: broadcasting Intent { act=android.intent.action.MEDIA_MOUNTED dat=file:///storage/emulated/0 flg=0x10 } from com.example.foo.bar (pid=17488, uid=10046) is not exported from uid 10014 due to receiver com.android.providers.downloads/.DownloadReceiver
INFO/ActivityManager(480): Start proc com.google.android.music:main for broadcast com.google.android.music/.store.MediaStoreImportService$Receiver: pid=17858 uid=10038 gids={50038, 3003, 1015, 1028}
INFO/MusicStore(17858): Database version: 50
INFO/MediaStoreImporter(17858): Update: incremental Added music: 0 Updated music: 0 Deleted music: 0 Created playlists: 0 Updated playlists: 0 Deleted playlists: 0 Inserted playlist items: 0 Deleted playlist items: 0 Removed orphaned playlist items: 0
The last line sounds encouraging in theory, but the values are always 0 even after new files had been pushed to the SD card (via adb push). On my older device (S2) it does remount the SD card.
I've added the following permissions to my AndroidManifest.xml but it behaves the same as without those permissions:
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Any ideas/alternatives?
Edit 1:
Note that I don't know any file paths of new or modified or deleted files. I just want to make sure the MediaStore is up-to-date.
Here's the sample code based on CommonsWare's answer:
MediaScannerConnection.scanFile(activity, new String[]{path}, null,
new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(final String path, final Uri uri) {
Log.i(TAG, String.format("Scanned path %s -> URI = %s", path, uri.toString()));
}
});
Even though in most of the cases, where one knows the files to be added/updated/etc. to the MediaStore, one should follow CommonsWare's answer, I wanted to post the my solution where I need to do it the rough way because I don't know the file paths. I use this mostly for testing/demoing:
Uri uri = Uri.fromFile(Environment.getExternalStorageDirectory());
activity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, uri));
BTW, no permissions are necessary for either solution.
using the popular way I found on SO
Faking ACTION_MEDIA_MOUNTED broadcasts has never been an appropriate solution IMHO.
Any ideas/alternatives?
Use MediaScannerConnection, such as via its scanFile() static method.
My answer is a little late, but it might help those, who save a new file, and would like to extend the media store by just that file on Android Kitkat: On Android Kitkat the intent ACTION_MEDIA_MOUNTED is blocked for non-system apps (I think, because scanning the whole filesystem is pretty expensive). But it is still possible to use the intent ACTION_MEDIA_SCANNER_SCAN_FILE to add a file to the media store:
File f = new File(path to the file you would like to add to the media store ...);
try {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(f);
mediaScanIntent.setData(uri);
sendBroadcast(mediaScanIntent);
} catch(Exception e) {
...
}