I'm developing a test with Espresso to test the profile image change function. I added the following lines in the #Before method in the test.
I create an intent with the image Uri, with my file provider, to return ever that my app goes to the gallery to pick an image.
Intent resultData = new Intent();
String filename = "img1.jpg";
String path = "mnt/sdcard/" + filename;
File f = new File(path);
Context context =InstrumentationRegistry.getInstrumentation().getContext();
Uri contentUri = getUriForFile(context, "com.otsuka.ikigai.fileprovider", f);
resultData.setData(contentUri);
Instrumentation.ActivityResult result = new Instrumentation.ActivityResult(Activity.RESULT_OK,resultData);
intending(not(isInternal())).respondWith(result);
The code of the activity that changes user image, calls the following method when it receives the intent,(I must not change it).
mProfileImage = CommonBitmapUtils.rotate(this, data.getData());
profileEdited = true;
imgUserPhoto.setImageBitmap(mProfileImage);
And I'm getting the following error:
android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
Caused by this line in the function rotate of the CommonBitmapUtils class:
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
The cursor has 0 rows don't know why.
Solved it by setting the following path. Without file providers and permissions.
I got the path by debugging the app without testing, and copying the value.
resultData.setData(Uri.parse("content://media/external/images/media/142583"));
Related
The Situation:
I decremented a Uri
First, I converted the Uri into a string and in turn into an int
Afterwhich, I did a -1, and then I got the string that looks exactly like a decremented string
However, when I parse the uri and try to setImageURI() on it,
it is showing "File error accessing recents directory (directory
doesn't exist?)."
Here is the code that I have used:
Uri ImageUri = data.getData();
String uri1 = ImageUri.toString();
//region uri2
String substr1 = uri1.substring(uri1.length()-3);
int substr1int = parseInt(substr1)-1;
String decrementedstr1 = new Integer(substr1int).toString();
int numberofchars1 = uri1.length()-3;
String firstcomponent1 = uri1.substring(0, numberofchars1);
String uri2 = firstcomponent1 + decrementedstr1;
//endregion
Uri test = Uri.parse(uri2);
animateobject.setImageURI(test);
Got this Error:
File error accessing recents directory (directory doesn't exist?).
After I used 'Debug App', it showed the error in more details:
java.lang.SecurityException: Permission Denial: reading
com.android.providers.media.MediaDocumentsProvider uri
content://com.android.providers.media.documents/document/image%3A1000002538
from pid=1309, uid=10925 requires that you obtain access using
ACTION_OPEN_DOCUMENT or related APIs
Note: This is in java and I'm using Android Studio to code.
Let's first get something straight. What is the meaning of that % character?
Well ... if you look at the URI Specification (RFC ....) the % is a percent encoding marker. The two characters after the % are hex digits, and the whole thing represents an ASCII character. In fact, %3A represents the colon character (:). So the unencoded "opaque" component of that URI is actually
//com.android.providers.media.documents/document/image:1000002538
Thus, the image (document) number is really 1000002538 and decrementing it should give 1000002537 as the image number.
I'm not entirely sure why your "string bashing" approach is failing, but you are decrementing just the last 3 digits of the image numbers ... and your example has 4 significant digits on the right end.
So here's how you should code it:
Uri imageUri = data.getData();
String[] pathSegments = imageUri.getSchemeSpecificPart().split("/");
String lastSegment = pathSegments[pathSegmentslength - 1);
String[] parts = lastSegment.split(":");
assert parts.length == 1 && "image".equals(parts[0]);
long imageNo = Long.parseLong(parts[1]);
imageNo--;
lastSegment = "image:" + imageNo;
pathSegments[pathSegments.length - 1] = lastSegment;
String path = String.join("/", pathSegments);
imageUri = Uri.Builder().scheme("content").opaquePart(path).build();
By calling getSchemeSpecificPart() we are getting the relevant part of the URI with the percent encoding decoded. Likewise, the Builder is going to re-apply encoding as required.
CAVEATS
This code is not compiled or tested. I don't have an Android dev platform.
For non-Android folks, this is using the Android Uri class not the Java SE URI class!
I am making a camera intent and storing the snapshot using the activity result, this is my code:
File imageFolder=new File(context.getExternalCacheDir(),"Cam/" + form);
imageFolder.mkdirs();
String random= UUID.randomUUID().toString();
String filename = random + ".jpg";
TakenImage = imageFolder + "/" + filename;
Intent camera=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
camera.putExtra(MediaStore.EXTRA_OUTPUT,TakenImage);
activityResultCamera.launch(camera);
But I get this error on the last line:
Key output expected Parcelable but value was a java.lang.String. The default value was returned.
Attempt to cast generated internal exception:
java.lang.ClassCastException: java.lang.String cannot be cast to android.os.Parcelable
Camera is an Intent, I also declared ActivityResultLauncher as Intent
ActivityResultLauncher<Intent> activityResultCamera = registerForActivityResult(...
So, what I am doing wrong?
EXTRA_OUTPUT needs to be:
A Uri...
With a scheme of content
You have:
A String...
That is a filesystem path that other apps cannot access on Android 10+
Use FileProvider to get a Uri that points to your desired location, and use that Uri in EXTRA_OUTPUT.
I have a programmed a custom exoplayer videoview to play videos from both internal memory and URL's. Now i want to check whether the video that is played presently in Videoview is from URL Stream or Internal storage. How can i check this?
You can use two methods to determine whether it's internal or remote.
Method 1 - Using Uri
Parse the given URI using Uri.parse(...) then use getScheme() to get the scheme. For (internal) files it will be file.
For example:
String file = "file:///path/of/your/file";
String remote = "https://www.example.com/your_video.mp4";
Uri fileUri = Uri.parse(file);
Uri remoteUri = Uri.parse(remote);
String fileScheme = fileUri.getScheme();
String remoteScheme = remoteUri.getScheme();
Log.d("Scheme", fileScheme); // prints file
Log.d("Scheme", remoteScheme); // prints https
Method 2 - Using File
Create a new File instance from the URI and check if it exists.
For example:
String file = "file:///path/of/your/file";
String remote = "https://www.example.com/your_video.mp4";
File fileFile = new File(file);
File remoteFile = new File(remote);
Log.d("File", "" + fileFile.exists()); // prints true if the file exists
Log.d("File", "" + remoteFile.exists()); // prints false always
I have a little bit strange question: this time everything works, but I can't understand why.
AFAIK it's possible to mount more than one sd card. Everything will be mounted to /mnt directory. (is it true?)
On my device there is only one sd card which mounted to /mnt/sdcard. And in my application I open files from it. I'm using next code:
private void open() {
// get file extension
String extension = "";
int dotIndex = downloadedFile.lastIndexOf('.');
if (dotIndex != -1) {
extension = downloadedFile.substring(dotIndex + 1, downloadedFile.length());
}
// create an intent
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
Uri data = Uri.fromFile(new File(downloadedFile));
String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (type == null || type.length() == 0) {
// if there is no acceptable mime type
type = "application/octet-stream";
}
intent.setDataAndType(data, type);
// get the list of the activities which can open the file
List resolvers = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (resolvers.isEmpty()) {
(new AlertDialog.Builder(context)
.setMessage(R.string.AttachmentUnknownFileType)
.setNeutralButton(R.string.NeutralButtonText, null)
.create()).show();
} else {
context.startActivity(intent);
}
}
Actually downloadedFile variable has value like file:///sdcard/mydir/myfile.txt. But the code works. Why? How Android understand what /sdcard/... is the same as /mnt/sdcard/...?
And main question: what happened if sd card will be mounted to other dir (for exmaple, /mnt/another-sd/ or even /media/sd)? What if more than one sd cards will be mounted: how android understand what card to use?
Thank you for any help! Have a good day!
It's simple android configueres the mounting over a settings file on phone boot so if there are mor sdcards Android will simply prefer one of them to set as
/sdcard/
so when the mount settings change your code is simply useless you can only hope the settings being untouched .
Every company that procuces Android smartphones use the "sdcard" path even custom roms like use it
I try the following code and it doesn't set the ringtone. The logcat entry for "ff" says null so I guess the URI isnt being concatenated properly?, I cant seem to figure out where in my code I am going wrong.
String filepath =Environment.getExternalStorageDirectory().toString()+"//media//audio//ringtones//bluemoon.mp3";
File ringtoneFile = new File(filepath);
ContentValues content = new ContentValues();
content.put(MediaStore.MediaColumns.DATA,ringtoneFile.getAbsolutePath());
content.put(MediaStore.MediaColumns.TITLE, "test");
content.put(MediaStore.MediaColumns.SIZE, 215454);
content.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mpeg");
content.put(MediaStore.Audio.Media.ARTIST, "artist");
content.put(MediaStore.Audio.Media.DURATION, 230);
content.put(MediaStore.Audio.Media.IS_RINGTONE, true);
content.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
content.put(MediaStore.Audio.Media.IS_ALARM, false);
content.put(MediaStore.Audio.Media.IS_MUSIC, false);
Log.i("BOOM", "the absolute path of the file is :"+ringtoneFile.getAbsolutePath());
Uri uri = MediaStore.Audio.Media.getContentUriForPath(
ringtoneFile.getAbsolutePath());
Uri newUri = getApplicationContext().getContentResolver().insert(uri, content);
Uri ringtoneUri = newUri;
Log.i("ff","the ringtone uri is :"+ringtoneUri);
RingtoneManager.setActualDefaultRingtoneUri(getApplicationContext(),
RingtoneManager.TYPE_RINGTONE,newUri);
Its possible data is not accurate for the file and its causing a problem. You may need to change:
audio/mpeg to audio/mp3
and duration to the actual duration of the file.
Another thing you may want to fix is your ringtone file declaration statement, try changing it to match this:
File k = new File(path, "mysong.mp3");
Also, I have a feeling your path is broken too..
Environment.getExternalStorageDirectory().toString()+"//media//audio//ringtones//bluemoon.mp3"
why with the two "//"?
It should be (for example):
../sdcard/media/ringtone