1

This code used to work on previous versions of Android, because the data from the intent in onActivityResult, would return null if the image came from the camera, and it would hold a Uri if the image was selected from the file system. However, on Lollipop, the camera intent is also returning a Uri. How do I know whether the image was taken with the camera or was selected from the file storage/gallery?

Here is my code:

private void openImageIntent() {

        // Determine Uri of camera image to save.
        final File root = new File(Environment.getExternalStorageDirectory()
                + File.separator + "Klea" + File.separator);
        root.mkdirs();
        final String fname = getUniqueImageFilename();
        final File sdImageMainDirectory = new File(root, fname);
        outputFileUri = Uri.fromFile(sdImageMainDirectory);

        // Camera.
        final List<Intent> cameraIntents = new ArrayList<Intent>();
        final Intent captureIntent = new Intent(
                android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        final PackageManager packageManager = getActivity().getPackageManager();
        final List<ResolveInfo> listCam = packageManager.queryIntentActivities(
                captureIntent, 0);
        for (ResolveInfo res : listCam) {
            final String packageName = res.activityInfo.packageName;
            final Intent intent = new Intent(captureIntent);
            intent.setComponent(new ComponentName(res.activityInfo.packageName,
                    res.activityInfo.name));
            intent.setPackage(packageName);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
            cameraIntents.add(intent);
        }

        // Filesystem.
        final Intent galleryIntent = new Intent();
        galleryIntent.setType("image/*");
        galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

        // Chooser of filesystem options.
        final Intent chooserIntent = Intent.createChooser(galleryIntent,
                getString(R.string.chose_source));

        // Add the camera options.
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,
                cameraIntents.toArray(new Parcelable[] {}));

        startActivityForResult(chooserIntent, REQUEST_IMAGE_CAPTURE);
    }

    private static String getUniqueImageFilename() {
        // TODO Auto-generated method stub
        String fileName = "img_" + System.currentTimeMillis() + ".jpg";
        return fileName;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d("reqCode", Integer.toString(requestCode));
        Log.d("resCode", Integer.toString(resultCode));
        Log.d("data", data.toString());
        getActivity();
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == REQUEST_IMAGE_CAPTURE) {
                final boolean isCamera;
                if (data == null) {
                    isCamera = true;
                } else {
                    final String action = data.getAction();
                    if (action == null) {
                        isCamera = false;
                    } else {
                        isCamera = action
                                .equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                    }
                }

                Uri selectedImageUri;
                if (isCamera) {
                    File file = new File(outputFileUri.toString());
                    Log.d("old file", file.toString());
                    String temp = file.toString().replace("file:", "");
                    Log.d("new file", temp);
                    selectedImageUri = Uri.parse(temp);
                } else {
                    Uri selectedImage = data.getData();
                    String[] filePathColumn = {MediaStore.Images.Media.DATA};

                    Cursor cursor = getActivity().getContentResolver().query(
                            selectedImage, filePathColumn, null, null, null);
                    cursor.moveToFirst();
                    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                    selectedImageUri = Uri.parse(cursor.getString(columnIndex));
                    cursor.close();
                }
            }
        }
    }
fadden
  • 51,356
  • 5
  • 116
  • 166
Kæmpe Klunker
  • 865
  • 1
  • 10
  • 27
  • Your code is based on [this answer](http://stackoverflow.com/questions/4455558/allow-user-to-select-camera-or-gallery-for-image/12347567#12347567), isn't it? – Alex Cohn Nov 11 '15 at 14:16
  • Your code makes the decision based not on Url, but rather on **data.getAction()**, so I don't know why Lollipop will make it different. – Alex Cohn Nov 11 '15 at 14:31
  • Because data used to return null if the image came from the camera. No reason to get data from a null object. Hence old questions about camera not returning image if specifying "intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);". – Kæmpe Klunker Nov 11 '15 at 14:36
  • *on Lollipop, the camera intent is also returning a Uri* - I have not found any proof for this statement. – Alex Cohn Nov 11 '15 at 16:02
  • Think it might have changed on KitKat. Try my code? "public void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d("data", data.toString()); }" Log shows: D/data﹕ Intent { dat=file:///storage/emulated/0/Klea/img_1447258303049.jpg } – Kæmpe Klunker Nov 11 '15 at 16:13
  • Checked on Nexus 5 with Marshmallow; the difference is that the **data** Intent does not bring **dat** inside. But still, the difference between file system and camera is obvious, see my answer coming very soon. – Alex Cohn Nov 11 '15 at 16:56
  • I have applied a solution that just checks if the Uri contains "file:/", because that is what i specify for my camera path. But don't think that's a bulletproof solution. – Kæmpe Klunker Nov 11 '15 at 17:06

1 Answers1

3

First of all, there can be no guarantee for you. The user can choose any app that declares the MediaStore.ACTION_IMAGE_CAPTURE intent in its manifest, and the app may decide to pick a picture from file system.

Second, have a look at the new createChooser() method that takes an IntentSender parameter to return the end user's choice for you to analyze, see this example (unfortunately, this is 22 and up).

Third, you provide outputFileUri as MediaStore.EXTRA_OUTPUT - this file will be hopefully created by camera, but ignored by the file system picker; now if you only clean up before calling launching the intent, you can easily check whether the file contains a new picture.

I agree with your conclusion that choosing based on data.dat (content://media/… -> file, file:/… -> camera) is not reliable enough.

So the bottom line, the easy but robust distinction can be made like this:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == REQUEST_IMAGE_CAPTURE) {
            final boolean isCamera = new File(outputFileUri.getPath()).length() > 0;
…
Community
  • 1
  • 1
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307