I'm trying to add some mp3 files from assets folder to android system sounds notification.
My problems are:
To add sound from assets to system sound I needed to storage permission with following code:
fun addSounds() {
val file = File(requireContext().filesDir, "notifications")
if (!file.exists())
file.mkdirs()
val soundFile = File(file.absolutePath + "/" + "longbeep.mp3")
requireContext().assets.open("long_beep.mp3").use { input ->
soundFile.outputStream().use { output ->
input.copyTo(output, 1024)
}
}
registerFile(soundFile, "ShahramLong2")
}
private fun registerFile(file: File, fileName: String) {
val values = ContentValues()
values.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath());
values.put(MediaStore.MediaColumns.TITLE, fileName);
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/ogg");
values.put(MediaStore.MediaColumns.SIZE, file.length());
values.put(MediaStore.Audio.Media.IS_RINGTONE, false);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
values.put(MediaStore.Audio.Media.IS_ALARM, false);
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
val generalaudiouri = Media.EXTERNAL_CONTENT_URI
val uri = Media.getContentUriForPath(file.absolutePath)
requireContext().contentResolver.delete(
Media.EXTERNAL_CONTENT_URI,
MediaStore.MediaColumns.DATA + "='" + file.getAbsolutePath() + "'",
null
)
requireContext().contentResolver.insert(Media.EXTERNAL_CONTENT_URI, values)
}
When changed registerFile to following code app crashed with exception
Caused by: java.lang.UnsupportedOperationException: Writing to internal storage is not supported.
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:174)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
Code is:
private fun registerFile(file: File, fileName: String) {
val values = ContentValues()
values.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath());
values.put(MediaStore.MediaColumns.TITLE, fileName);
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/ogg");
values.put(MediaStore.MediaColumns.SIZE, file.length());
values.put(MediaStore.Audio.Media.IS_RINGTONE, false);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
values.put(MediaStore.Audio.Media.IS_ALARM, false);
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
val generalaudiouri = Media.EXTERNAL_CONTENT_URI
val uri = Media.getContentUriForPath(file.absolutePath)
// use uri instead of Media.EXTERNAL_CONTENT_URI
requireContext().contentResolver.delete(
uri!!,
MediaStore.MediaColumns.DATA + "='" + file.getAbsolutePath() + "'",
null
)
requireContext().contentResolver.insert(uri!!, values)
}
Another problem is apparently this line does not work:
requireContext().contentResolver.delete(
Media.EXTERNAL_CONTENT_URI,
MediaStore.MediaColumns.DATA + "='" + file.getAbsolutePath() + "'",
null
)
The sound is added several times.
Related
My code runs perfect on any Android lower then Android 11.
On Android 11 (specifically on Pixel2 & Pixel3 emulator and real devices) the file descriptor fail to find the file after inserting it to the media store.
If I change the relative path on the second line to be only the Environment.DIRECTORY_MOVIES path - it works
String relativeLocation = Environment.DIRECTORY_MOVIES;
This is my code:
String mimeType = "video/mp4";
String relativeLocation = Environment.DIRECTORY_MOVIES + File.separator + SUB_DIRECTORY_NAME ;
shortFileName = getDateStamp() + selectedExtension;
videoContentValues = new ContentValues();
videoContentValues.put(MediaStore.Video.Media.TITLE, shortFileName);
videoContentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, shortFileName);
videoContentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
videoContentValues.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
videoContentValues.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
videoContentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
videoContentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
videResolver = mContext.getContentResolver();
Uri contentUri = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
videoUri = videResolver.insert(contentUri, videoContentValues);
if (videoUri == null) {
throw new IOException("Failed to create new MediaStore record.");
}
pfd = mContext.getContentResolver().openFileDescriptor(videoUri, "w");
mMediaRecorder.setOutputFile(pfd.getFileDescriptor());
The code runs OK until it gets to the openFileDescriptor which return the following error:
java.io.FileNotFoundException: java.io.FileNotFoundException: No item at content://media/external_primary/video/media/47
What am I doing wrong?
Update 1:
More info:
I am still requesting WRITE_EXTERNAL_STORAGE and making sure it is allowed before start recording
The following code works in the same camera app on Android 11 Pixel 2 emulator to save pics:
String mimeType = "image/jpeg";
final String relativeLocation = Environment.DIRECTORY_PICTURES + File.separator + SUB_DIRECTORY_NAME;
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, createImageFileNameQ());
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
ContentResolver resolver = mContext.getContentResolver();
OutputStream stream = null;
Uri uri = null;
try {
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
uri = resolver.insert(contentUri, contentValues);
try {
OutputStream fos = resolver.openOutputStream(uri);
fos.write(data);
fos.flush();
fos.close();
}
catch (Exception ex) {
Log.e(TAG, ex.toString());
}
Update 2:
If I write on the second line "String relativeLocation = Environment.DIRECTORY_PICTURES + File.separator + SUB_DIRECTORY_NAME;" and not DIRECTORY_MOVIES :
It works!#!!
Video files are saved on Videos\Sub_Directory
Update 3:
Now on the emulators:
no trick helps to make relative path.
And also the pics cannot be saved to relative path
String mimeType = "image/jpeg"; String relativeLocation = Environment.DIRECTORY_PICTURES + File.separator + SUB_DIRECTORY_NAME;
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, createImageFileNameQ());
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
ContentResolver resolver = mContext.getContentResolver();
OutputStream stream = null;
Uri uri = null;
try {
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
uri = resolver.insert(contentUri, contentValues);
try {
OutputStream fos = resolver.openOutputStream(uri);
fos.write(data);
fos.flush();
fos.close();
} catch (Exception ex) {
Log.e(TAG, ex.toString());
}
} catch (Exception e) {}
I have opened a ticket to Google/Android with full recording of the emulator debug messages like they asked. they said: "interesting, they will look into it". they did not answer - but they have fixed it for the latest Android 11 release. Security patch Nov. 2020. So - problem was solved.
I have left a bug fix in my code in case somebody did not get the last android 11 update. In case of this error - I set IsAndroid11SaveOnSubDirectoryEnabled variable to false
String relativeLocation = Environment.DIRECTORY_MOVIES + File.separator + SUB_DIRECTORY_NAME;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q && IsAndroid11SaveOnSubDirectoryEnabled == false)
{
relativeLocation = Environment.DIRECTORY_MOVIES + File.separator + "$" + SUB_DIRECTORY_NAME;
Log.e(TAG, "Recording on $SubDirectory");
}
Edit II:
I got an answer from Google/Android that maybe I have a ".nomedia" file in the directory, and so - the Media store cannot insert/index new files. (.nomedia is a file that tells the gallery not to read the medias on this folder, it applies until Android 10, on Android 11 - this file cannot be created or deleted in the movies folder because it is not media). But it was not correct - the log files and recording that I have sent to Google/Android were from an Android 11 Emulator which did not have this file.
Edit III - Since Dilijeet asked, IsAndroid11SaveOnSubDirectoryEnabled is a boolean that I save to the SharedPreference. here is the code - whenever the recording crash on IOExcpetion & Android 11 - I assume it is the subdirectory problem, and set this boolean for further recordings.
catch (IOException ex)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && IsAndroid11SaveOnSubDirectoryEnabled == true) {
mSharedPreferences.edit().putBoolean("chkSaveOnSubDirectory", false).apply();
IsAndroid11SaveOnSubDirectoryEnabled = false;
}
I am developing an android application in which there is a scenario that we need to convert a file's absolute path (/storage/emulated/0/..../1584362593949.pdf) to content URI(content://)
I have tried converting for the file types such as Audio and video with the help of content resolver and there was no issue I faced but stuck at converting for PDF documents.
Check the code snippet below
public Uri convertFileUriToContentUri(String filePath, String title) {
String fileType = title.substring(title.lastIndexOf(".") + 1);
File file = new File(filePath);
Uri base = null;
//creating content values of size 4
ContentValues values = new ContentValues(4);
long current = System.currentTimeMillis();
switch (fileType) {
case "mp3":
values.put(MediaStore.Audio.Media.TITLE, "audio" + file.getName());
values.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000));
values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mp3");
values.put(MediaStore.Audio.Media.DATA, file.getAbsolutePath());
base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
break;
case "pdf":
// I am Stuck here as MediaStore does not provide support to documents
break;
case "mp4":
values.put(MediaStore.Video.Media.TITLE, "video" + file.getName());
values.put(MediaStore.Video.Media.DATE_ADDED, (int) (current / 1000));
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
values.put(MediaStore.Video.Media.DATA, file.getAbsolutePath());
base = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
break;
}
//creating content resolver and storing it in the external content uri
ContentResolver contentResolver = context.getContentResolver();
Uri newUri = contentResolver.insert(base, values);
//sending broadcast message to scan the media file so that it can be available
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri));
return newUri;
}
Please help me find out the solution.
I created a simple android app for adding frames and cropping images, now after the editing is done the pictures are saved in android root>app folder but non of these pictures show up in the gallery, here is My code
/**
* Create a File for saving an image or video
*/
private File getOutputMediaFile() {
// To be safe, you should check that the SDCard is mounted
// File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
// + "/Android/data"
// + getApplicationContext().getPackageName()
// + "/Files" + Global.AppFolder);
File root = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "/" + Global.AppFolder);
// Create the storage directory if it does not exist
if (!root.exists()) {
if (!root.mkdirs()) {
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(new Date());
File mediaFile;
String mImageName = "MI_" + timeStamp + ".jpg";
mediaFile = new File(root.getAbsolutePath(), mImageName);
return mediaFile;
}
private String getRealPathFromURI(Uri uri) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor == null) {
return uri.getPath();
} else {
cursor.moveToFirst();
String s = cursor.getString(cursor.getColumnIndex("_data"));
cursor.close();
return s;
}
}
By the way I am a newbie and don't have a lot of experience with android coding so detailed answers and references(for further learning) shall be highly appreciated.
try this add below code after saving image
ContentValues values = new ContentValues();
values.put(Images.Media.TITLE, "title");
values.put(Images.Media.DESCRIPTION, "description");
values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(Images.ImageColumns.BUCKET_ID, root.toString().toLowerCase(Locale.US).hashCode());
values.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, root.getName().toLowerCase(Locale.US));
values.put("_data", root.getAbsolutePath());
ContentResolver cr = getContentResolver();
cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Add these code after you save the image
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
The Media Scanning is only done when the system Bootup. So you need to tell the media scanner to re-scan the files.
I am trying to give users an option to set image as wallpaper/whatsapp dp like this.
But I'm stuck with this code
Uri sendUri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.a_day_without_thinking_mobile);
Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
intent.setDataAndType(sendUri, "image/jpg");
intent.putExtra("mimeType", "image/jpg");
startActivity(Intent.createChooser(intent,"Set As"));
It shows a dialog that no apps can perform this action.
I also tried to check my Uri through this method
ContentResolver cr = getContentResolver();
String[] projection = {MediaStore.MediaColumns.DATA};
Cursor cur = cr.query(sendUri, projection, null, null, null);
if (cur != null) {
if (cur.moveToFirst()) {
String filePath = cur.getString(0);
if (new File(filePath).exists()) {
Log.d("URI: ","File path exist");
} else {
Log.d("URI: ","File not found");
}
} else {
Log.d("URI: ","URI ok but no enty found");
}
cur.close();
} else {
Log.d("URI: ","URI was invalid for some other reason");
}
And It always returned that the URI was invalid. But I'm sure that the image is valid jpg and is present in raw folder.
I tried changing URI paths but to no success.
Android file read format has been changed after targetSdkVersion >= 24
You can find the details here;
https://stackoverflow.com/a/38858040/1367450
Am trying to insert an aduio file in the android phone. the same code works fin in android
2.1
but when i try to use it in Android 2.2; the inserting in ContentResolver succseed but i can't
find my audio file in the gallery (so the user can't see it)
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+path+filename)));
File k = new File(path, filename);
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Media.DATA, k.getAbsolutePath());
values.put(MediaStore.Audio.Media.TITLE, aud.TITLE);
values.put(MediaStore.Audio.Media.MIME_TYPE, aud.MIME_TYPE);
values.put(MediaStore.Audio.Media.ARTIST, aud.ARTIST);
values.put(MediaStore.Audio.Media.IS_RINGTONE, aud.IS_RINGTONE);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, aud.IS_NOTIFICATION);
values.put(MediaStore.Audio.Media.IS_ALARM, aud.IS_ALARM);
values.put(MediaStore.Audio.Media.IS_MUSIC, aud.IS_MUSIC);
//Insert it into the database
context.getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
Try adding "file:///" that will work