I have a simple Android app that tries to take a picture and send it to a server as HTTP POST with multipart data. The problem is that the the behavior of Androids Intent is different on some phones. When I run
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 0);
on HTC One (Android 4.1.1) and Sony Xperia Z1 (Android 4.4.4), it stores the image in the gallery and calls like the one below works:
data.getData().getPath();
(data is an instance of Intent), whereas when I run the same code on LG Nexus 5 (Android 4.4.4), the image is not stored, and
data.getData();
returns null.
What I need is a way to store the image (temporally), so I can transfer it to the server.
Looks like there could be a bug in the recent android stock camera, please see this issue report on android. According to the bug, the data field returned by the camera intent could come back null in default behavior. (MediaStore.EXTRA_OUTPUT is not used).
To guarantee you always get image, allocate a file yourself and pass that uri in camera intent extras as MediaStore.EXTRA_OUTPUT
The best practice in allocating a temporary image file is to ensure the underlying media is mounted, see this sample code snippet on android developer site. On a successful completion of camera intent, just use the file uri you allocated...do not use getData (could be null).
Related
I recently updated my Poco X3 NFC 64GB test device to Android 11:
MIUI Global 12.0.8(RJGEUXM)
Android 11 RKQ1.200826.002
Ever since I am unable to take or pick photos in my app. On other Android 11 devices (and emulator) everything works fine. The app is compiled to API level 30.
I start the photo picker chooser like this:
private void pickPhoto() {
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivityForResult(intent, 100);
}
}
This works fine, but after I have picked a photo it returns to the app, triggering onActivityResult with resultCode 0 (RESULT_CANCELED) and data is null too. On other Android 11 devices I can retrieve the photo from the data, but not on my Poco. Yes I did add the necessary query to the manifest file (else I wouldn't be able to open the picker in the first place).
When I try to fetch a photo from the camera I have exactly the same issue. Again on other Android 11 devices this works fine. So yes I did add and use the necessary file provider.
Sometimes a toast pops up about not having granted the right permissions. Do any of you guys have a Poco phone and like to try it out? I wonder if the Poco rom is just broken or something.
UPDATE
I've narrowed down the problem. It turns out that if startActivity() starts a camera/gallery activity directly it works fine. However if you're prompted a chooser first (e.g. because you have multiple gallery apps) it goes wrong.
So if you pick a gallery app and say to always use it in the future, the next time it will open that gallery app directly and then it works correctly.
If you use Intent.createChooser() it never works right. Even if it contains only one intent that is launched directly without prompting a chooser it fails to return a photo.
Can we agree that this is a MIUI bug?
I want my app to list/display only the phone's photos ( nothing else ) so that the user could select one of them whose bitmap will then be dealt later on by my remaining code.
The problem is that the code below instead of displaying photos directly, it first displays TWO FOLDERS ( Photos and Camera ) where photos are stored/grouped and waits for selection. How to bypass folders display/selection and go straight to photos display/selection ?
Here is the current code:
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(intent,0);
I want my app to list/display only the phone's photos ( nothing else )
Query the MediaStore to find images and handle the UI yourself.
The problem is that the code below instead of displaying photos directly, it first displays TWO FOLDERS ( Photos and Camera )
It does that on your device. The results on other devices will vary, and there are ~2 billion of them, spread over ~20,000 device models. You are delegating to an indeterminate third-party app, which will vary by device and by user. It may result in a chooser for the user to select one of several apps that can handle your Intent.
If you do not like that behavior, query the MediaStore to find images and handle the UI yourself. This is more work, but you have complete control over the UI.
I'm working with some legacy code and the camera is opened using
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
Which is fine. However, some code is running when the camera app is open (I'm not sure entirely why), but it does something if the camera app is in front of the user. The "top" app is retrieved, and then the code that checks if the camera is on top is:
boolean isCameraOnTop = topName.toLowerCase().indexOf("camera") != -1;
This was working fine for some time but we've been testing with a new device whose default camera app name is NOT "camera", but something else ("org.codeaurora.snapcam" if you must know). This approach seems flimsy as any device can have any default camera app.
SO, my question is, when I launch the camera app via the ACTION_IMAGE_CAPTURE intent, how can I find the app that actually gets opened?
After some searching, I found the solution:
activity.getPackageManager().resolveActivity(cameraIntent, PackageManager.MATCH_DEFAULT_ONLY).activityInfo.packageName;
I have the following code to display an imagepicker.
After user picks an image onActivityResult gets called, to return me the data for the selected image.
On kindle however, I get a resultCode of 0, and data as null.
Anyone else has noticed this problem before?
This problem happens only on kindle fire.
startActivityForResult(new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI), SELECT_PICTURE);
I'm running into this exact same issue. Prior to the recent Kindle Fire update, which happened a few days ago for me, picking images from the gallery worked fine for me.
So the most recent Kindle Fire update must have introduced this bug.
You can get data back from such calls in two ways: either in the actual intent data, or in Intent.EXTRA_STREAM. If you get something back in EXTRA_STREAM it will be a mediastore content:// URL which you'd use a Cursor to look up.
I have an app that user's can draw with, and then 'export' that drawing as a .png file to external storage, if present. Generating the PNG, copying the file to external all work like a charm, but a rather unique problem happens; after the export, if the user navigates to the image via My files (Samsung Tab running 2.2 in this case), they can see the .png file, but when they open it, the screen is black for about 10 seconds... then they see the image, Additionally, the images don't show up in the user's 'Gallery' app either.
Now, if the user connects the device to the computer via USB, or reboots the device, they can access the images no problem from My files, and they appear in 'Gallery' from that point forward, but again, any newly esported files experience the same problems until they cycle/connect the device again.
My thinking was that this had to be related to the Media Scanner (at least in the case of the 'Gallery' problem, it most certainly is).
So, as I am targetting Api 8+, I am trying to use the static MediaScannerConnection.scanFile() method to have the OS re-scan and add my images into the Gallery, etc. Also hoping this solves the issue of the strange delay in opening the images. Here is my code:
MediaScannerConnection.scanFile(
context,
new String[] { "/mnt/sdcard/MyApp" },
null,
null
);
LogCat gives me the following entries when I export an image, and thus run the above call:
DEBUG/MediaScannerService(2567): IMediaScannerService.scanFile: /mnt/sdcard/MyApp mimeType: null
DEBUG/MediaScannerService(2567): onStartCommand : intent - Intent { cmp=com.android.providers.media/.MediaScannerService (has extras) }
DEBUG/MediaScannerService(2567): onStartCommand : flags [0], startId [1]
DEBUG/MediaScannerService(2567): ServiceHandler:handleMessage volume[null], filePath[/mnt/sdcard/MyApp]
DEBUG/MediaProvider(2567): getSdSerial() sd state = removed
INFO/Database(2567): sqlite returned: error code = 17, msg = prepared statement aborts at 43: [SELECT DISTINCT sd_serial FROM images WHERE sd_serial LIKE 'external_0x%']
ERROR/MediaProvider(2567): removeMediaDBData called
DEBUG/MediaScanner(2567): prescan enter: path - /mnt/sdcard/MyApp
DEBUG/MediaScanner(2567): prescan return
So, it looks like the MediaScanner is getting the correct location, but is failing to find the SD card, which is correct, and failing. The Samsung Tab has built-in non-SD external storage, which Android gives access to via Environment.getExternalStorageDirectory(). How do I tell it to scan the non-SD storage?
Any ideas how to proceed?
Paul
Found the solution here, which involves sending a broadcast request to the media scanner via an Intent:
How to update the Android media database
Never did figure out the issue with MediaScannerConnection.scanFile.
Whenever you add a file, let MediaStore Content Provider knows about it using
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(imageAddedOrDeleted)));
Main advantage: work with any mime type supported by MediaStore
For deletion: just use getContentResolver().delete(uri, null, null)