chromium/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialog.java

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.components.browser_ui.photo_picker;

import android.content.ContentResolver;
import android.net.Uri;

import androidx.activity.OnBackPressedCallback;

import org.chromium.components.browser_ui.widget.FullscreenAlertDialog;
import org.chromium.ui.base.PhotoPicker;
import org.chromium.ui.base.PhotoPickerListener;
import org.chromium.ui.base.WindowAndroid;

import java.util.List;

/**
 * UI for the photo chooser that shows on the Android platform as a result of <input type=file
 * accept=image > form element.
 */
public class PhotoPickerDialog extends FullscreenAlertDialog
        implements PhotoPickerToolbar.PhotoPickerToolbarDelegate, PhotoPicker {
    // Our window.
    private WindowAndroid mWindowAndroid;

    // The category we're showing photos for.
    private PickerCategoryView mCategoryView;

    // A wrapper around the listener object, watching to see if an external intent is launched.
    private PhotoPickerListenerWrapper mListenerWrapper;

    // Whether the wait for an external intent launch is over.
    private boolean mDoneWaitingForExternalIntent;

    /**
     * A wrapper around {@link PhotoPickerListener} that listens for external intents being
     * launched.
     */
    private static class PhotoPickerListenerWrapper implements PhotoPickerListener {
        // The {@link PhotoPickerListener} to forward the events to.
        PhotoPickerListener mListener;

        // Whether the user selected to launch an external intent.
        private boolean mExternalIntentSelected;

        /** The constructor, supplying the {@link PhotoPickerListener} object to encapsulate. */
        public PhotoPickerListenerWrapper(PhotoPickerListener listener) {
            mListener = listener;
        }

        // PhotoPickerListener:
        @Override
        public void onPhotoPickerUserAction(@PhotoPickerAction int action, Uri[] photos) {
            mExternalIntentSelected = false;
            if (action == PhotoPickerAction.LAUNCH_GALLERY
                    || action == PhotoPickerAction.LAUNCH_CAMERA) {
                mExternalIntentSelected = true;
            }

            mListener.onPhotoPickerUserAction(action, photos);
        }

        @Override
        public void onPhotoPickerDismissed() {
            mListener.onPhotoPickerDismissed();
        }

        /** Returns whether the user picked an external intent to launch. */
        public boolean externalIntentSelected() {
            return mExternalIntentSelected;
        }
    }

    /**
     * The PhotoPickerDialog constructor.
     *
     * @param windowAndroid The window of the hosting Activity.
     * @param contentResolver The ContentResolver to use to retrieve image metadata from disk.
     * @param listener The listener object that gets notified when an action is taken.
     * @param multiSelectionAllowed Whether the photo picker should allow multiple items to be
     *     selected.
     * @param mimeTypes A list of mime types to show in the dialog.
     */
    public PhotoPickerDialog(
            WindowAndroid windowAndroid,
            ContentResolver contentResolver,
            PhotoPickerListener listener,
            boolean multiSelectionAllowed,
            List<String> mimeTypes) {
        super(windowAndroid.getContext().get());

        mWindowAndroid = windowAndroid;
        mListenerWrapper = new PhotoPickerListenerWrapper(listener);

        // Initialize the main content view.
        mCategoryView =
                new PickerCategoryView(windowAndroid, contentResolver, multiSelectionAllowed, this);
        mCategoryView.initialize(this, mListenerWrapper, mimeTypes);
        setView(mCategoryView);
        getOnBackPressedDispatcher()
                .addCallback(
                        new OnBackPressedCallback(true) {
                            @Override
                            public void handleOnBackPressed() {
                                // Pressing Back when a video is playing, should only end the video
                                // playback.
                                boolean videoWasStopped = mCategoryView.closeVideoPlayer();
                                if (!videoWasStopped) {
                                    setEnabled(false);
                                    getOnBackPressedDispatcher().onBackPressed();
                                }
                            }
                        });
    }

    @Override
    public void dismiss() {
        if (!mListenerWrapper.externalIntentSelected() || mDoneWaitingForExternalIntent) {
            super.dismiss();
            mCategoryView.onDialogDismissed();
            mListenerWrapper.onPhotoPickerDismissed();
        }
    }

    /** Cancels the dialog in response to a back navigation. */
    @Override
    public void onNavigationBackCallback() {
        cancel();
    }

    // PhotoPicker:

    @Override
    public void onExternalIntentCompleted() {
        mDoneWaitingForExternalIntent = true;
        dismiss();
    }

    public PickerCategoryView getCategoryViewForTesting() {
        return mCategoryView;
    }
}