Intent to choose between the camera or the gallery

2019-04-20 15:44发布

问题:

I'm trying to launch an intent to pick a image from the camera or the android's gallery. I checked THIS post and currently my code is near to work:

private Intent getPickIntent() {
    final List<Intent> intents = new ArrayList<Intent>();
    if (allowCamera) {
        setCameraIntents(intents, cameraOutputUri);
    }
    if (allowGallery) {
        intents.add(new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI));
    }

    if (intents.isEmpty()) return null;
    Intent result = Intent.createChooser(intents.remove(0), null);
    if (!intents.isEmpty()) {
        result.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(new Parcelable[] {}));
    }
    return result;
}

private void setCameraIntents(List<Intent> cameraIntents, Uri output) {
    final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    final PackageManager packageManager = context.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, output);
        cameraIntents.add(intent);
    }
}

When I set allowCamera=true it works correctly.

When I set allowGallery=true it shows the following chooser:

But if I set allowCamera=true and allowGallery =true the chooser shown is:

And if you select Android System then the first chooser is shown.

I'd like the chooser to be something like:

How can I "expand" the Android System option?

回答1:

In your linked post you can find the solution. The difference to your code is how the gallery intent is created:

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

Not with ACTION_PICK how you did but with ACTION_GET_CONTENT. It seems that if a single ACTION_PICK is in the list (a "container intent"), the system traverses it to display the content of the pick, but as soon you include the camera intent it can't traverse anymore (since there is one direct intent and one container intent).

In the comment of this answer you find the difference between ACTION_PICK and ACTION_GET_CONTENT.

There are some solutions available which recommend to use a custom dialog. But this dialog will not have the standards icons (see develper docs here). So I recommend to stay at your solution and just fix the hierarchie issue.



回答2:

            Intent galleryintent = new Intent(Intent.ACTION_GET_CONTENT, null);
            galleryintent.setType("image/*");

            Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);

            Intent chooser = new Intent(Intent.ACTION_CHOOSER);
            chooser.putExtra(Intent.EXTRA_INTENT, galleryintent);
            chooser.putExtra(Intent.EXTRA_TITLE, "Select from:");

            Intent[] intentArray = { cameraIntent };
            chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
            startActivityForResult(chooser, REQUEST_PIC);


回答3:

## Intent to choose between Camera and Gallery Heading and can crop image after capturing from camera ##


public void captureImageCameraOrGallery() {

        final CharSequence[] options = { "Take photo", "Choose from library",
                "Cancel" };
        AlertDialog.Builder builder = new AlertDialog.Builder(
                Post_activity.this);

        builder.setTitle("Select");

        builder.setItems(options, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
                if (options[which].equals("Take photo")) {
                    try {
                        Intent cameraIntent = new Intent(
                                android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                        startActivityForResult(cameraIntent, TAKE_PICTURE);
                    } catch (ActivityNotFoundException ex) {
                        String errorMessage = "Whoops - your device doesn't support capturing images!";

                    }

                } else if (options[which].equals("Choose from library")) {
                    Intent intent = new Intent(
                            Intent.ACTION_PICK,
                            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                    startActivityForResult(intent, ACTIVITY_SELECT_IMAGE);
                } else if (options[which].equals("Cancel")) {
                    dialog.dismiss();

                }

            }
        });
        dialog = builder.create();
        dialog.getWindow().getAttributes().windowAnimations = R.style.dialog_animation;

        dialog.show();

    }

public void onActivityResult(int requestcode, int resultcode, Intent intent) {
        super.onActivityResult(requestcode, resultcode, intent);
        if (resultcode == RESULT_OK) {
            if (requestcode == TAKE_PICTURE) {
                picUri = intent.getData();
                startCropImage();
            } else if (requestcode == PIC_CROP) {
                Bitmap photo = (Bitmap) intent.getExtras().get("data");
                Drawable drawable = new BitmapDrawable(photo);
                backGroundImageLinearLayout.setBackgroundDrawable(drawable);
            } else if (requestcode == ACTIVITY_SELECT_IMAGE) {
                Uri selectedImage = intent.getData();
                String[] filePath = { MediaStore.Images.Media.DATA };
                Cursor c = getContentResolver().query(selectedImage, filePath,
                        null, null, null);
                c.moveToFirst();
                int columnIndex = c.getColumnIndex(filePath[0]);
                String picturePath = c.getString(columnIndex);
                c.close();
                Bitmap thumbnail = (BitmapFactory.decodeFile(picturePath));
                Drawable drawable = new BitmapDrawable(thumbnail);
                backGroundImageLinearLayout.setBackgroundDrawable(drawable);

            }
        }
    }

private void startCropImage() {
        try {
            Intent cropIntent = new Intent("com.android.camera.action.CROP");
            cropIntent.setDataAndType(picUri, "image/*");
            cropIntent.putExtra("crop", "true");
            cropIntent.putExtra("aspectX", 1);
            cropIntent.putExtra("aspectY", 1);
            // indicate output X and Y
            cropIntent.putExtra("outputX", 256);
            cropIntent.putExtra("outputY", 256);
            // retrieve data on return
            cropIntent.putExtra("return-data", true);
            // start the activity - we handle returning in onActivityResult
            startActivityForResult(cropIntent, PIC_CROP);
        } catch (ActivityNotFoundException anfe) {
            // display an error message
            String errorMessage = "Whoops - your device doesn't support the crop action!";
            Toast toast = Toast
                    .makeText(this, errorMessage, Toast.LENGTH_SHORT);
            toast.show();
        }
    }


回答4:

You may need to create a custom dialog for this:

Here is the code for the method which is to be called when the user clicks on a particular button:

private void ChooseGallerOrCamera() {
    final CharSequence[] items = { "Take Photo", "Choose from Gallery",
            "Cancel" };

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setTitle("Add Photo!");
    builder.setItems(items, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int item) {
            if (items[item].equals("Take Photo")) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                File f = new File(android.os.Environment
                        .getExternalStorageDirectory(), "MyImage.jpg");
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
                startActivityForResult(intent, REQUEST_CAMERA);
            } else if (items[item].equals("Choose from Gallery")) {
                Intent intent = new Intent(
                        Intent.ACTION_PICK,
                        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                intent.setType("image/*");
                startActivityForResult(
                        Intent.createChooser(intent, "Select File"),
                        SELECT_FILE);
            } else if (items[item].equals("Cancel")) {
                dialog.dismiss();
            }
        }
    });
    builder.show();
}

And the code for handling onActivityResult():

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        Bitmap mBitmap;
        if (requestCode == REQUEST_CAMERA) {
            File camFile = new File(Environment.getExternalStorageDirectory()
                    .toString());
            for (File temp : camFile.listFiles()) {
                if (temp.getName().equals("MyImage.jpg")) {
                    camFile = temp;
                    break;
                }
            }
            try {

                BitmapFactory.Options btmapOptions = new BitmapFactory.Options();

                mBitmap = BitmapFactory.decodeFile(camFile.getAbsolutePath(),
                        btmapOptions);
                //Here you have the bitmap of the image from camera

            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (requestCode == SELECT_FILE) {
            Uri selectedImageUri = data.getData();

            String tempPath = getPath(selectedImageUri, MyActivity.this);
            BitmapFactory.Options btmapOptions = new BitmapFactory.Options();
            mBitmap = BitmapFactory.decodeFile(tempPath, btmapOptions);

            //Here you have the bitmap of the image from gallery
        }
    }
}

public String getPath(Uri uri, Activity activity) {
    String[] projection = { MediaColumns.DATA };
    Cursor cursor = activity
            .managedQuery(uri, projection, null, null, null);
    int column_index = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
}

EDIT: Try Using this:

private void letUserTakeUserTakePicture() {

    Intent pickIntent = new Intent();
    pickIntent.setType("image/*");
    pickIntent.setAction(Intent.ACTION_GET_CONTENT);
    Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT,
            Uri.fromFile(getTempFile(getActivity())));

    String pickTitle = "Select or take a new Picture"; // Or get from strings.xml
    Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
    chooserIntent.putExtra
            (Intent.EXTRA_INITIAL_INTENTS, new Intent[]{takePhotoIntent});

    startActivityForResult(chooserIntent, Values.REQ_CODE_TAKEPICTURE);
}


回答5:

Intent for showing camera and video files in activity chooser:

    Intent galleryintent = new Intent(Intent.ACTION_GET_CONTENT, null);
    galleryintent.setType("video/*");

    Intent cameraIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

    Intent chooser = new Intent(Intent.ACTION_CHOOSER);
    chooser.putExtra(Intent.EXTRA_INTENT, galleryintent);
    chooser.putExtra(Intent.EXTRA_TITLE, "Select from:");

    Intent[] intentArray = { cameraIntent };
    chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
    startActivityForResult(chooser, REQUEST_VIDEO_CAPTURE);


回答6:

Your code already very achieve the goal. Just exchange the gallery and camera add order.

if (allowGallery) {
    intents.add(new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI));
}
if (allowCamera) {
    setCameraIntents(intents, cameraOutputUri);
}

Here's my test result. Appearance difference since my OS is Android Nougat(7.0)

The first screenshot is in your order, the second is after exchange. Just like you said, in first situation, click the system logo will show gallery items.