chromium/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogDelegate.java

// Copyright 2016 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.permissions;

import android.graphics.Bitmap;

import androidx.core.util.Pair;

import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods;

import org.chromium.ui.base.WindowAndroid;

import java.util.ArrayList;
import java.util.List;

/**
 * Delegate class for modal permission dialogs. Contains all of the data displayed in a prompt,
 * including the button strings, message text and the icon.
 *
 * This class is also the interface to the native-side permissions code. When the user responds to
 * the permission dialog, the decision is conveyed across the JNI so that the native code can
 * respond appropriately.
 */
@JNINamespace("permissions")
public class PermissionDialogDelegate {
    /** The native-side counterpart of this class */
    private long mNativeDelegatePtr;

    /** The controller for this class */
    private PermissionDialogController mDialogController;

    /** The window for which to create the dialog. */
    private WindowAndroid mWindow;

    /** The icon to display in the dialog. */
    private int mDrawableId;

    /** Text shown in the dialog. */
    private String mMessageText;

    /** Text to display on the persistent grant button, e.g. "Allow". */
    private String mPositiveButtonText;

    /** Text The text to display on the persistent deny button, e.g. "Block". */
    private String mNegativeButtonText;

    /**
     * Text to display on the ephemeral grant button, e.g. "Allow this time". May be an empty string
     * in which case the button should not be shown.
     */
    private String mPositiveEphemeralButtonText;

    /** Whether to show the persistent grant button first, followed by the ephemeral option. */
    private boolean mShowPositiveNonEphemeralAsFirstButton;

    /** The {@link ContentSettingsType}s requested in this dialog. */
    private int[] mContentSettingsTypes;

    /**
     * Defines a (potentially empty) list of ranges represented as pairs of <startIndex, endIndex>,
     * which shall be used by the UI to format the specified ranges as bold text.
     */
    private List<Pair<Integer, Integer>> mBoldedRanges = new ArrayList<>();

    public WindowAndroid getWindow() {
        return mWindow;
    }

    public int[] getContentSettingsTypes() {
        return mContentSettingsTypes.clone();
    }

    public boolean canShowEphemeralOption() {
        return !mPositiveEphemeralButtonText.isEmpty();
    }

    public int getDrawableId() {
        return mDrawableId;
    }

    public String getMessageText() {
        return mMessageText;
    }

    public List<Pair<Integer, Integer>> getBoldedRanges() {
        return mBoldedRanges;
    }

    public String getPositiveButtonText() {
        return mPositiveButtonText;
    }

    public String getNegativeButtonText() {
        return mNegativeButtonText;
    }

    public String getPositiveEphemeralButtonText() {
        return mPositiveEphemeralButtonText;
    }

    public boolean shouldShowPositiveNonEphemeralAsFirstButton() {
        return mShowPositiveNonEphemeralAsFirstButton;
    }

    public void onAccept() {
        assert mNativeDelegatePtr != 0;
        PermissionDialogDelegateJni.get().accept(mNativeDelegatePtr, PermissionDialogDelegate.this);
    }

    public void onAcceptThisTime() {
        assert mNativeDelegatePtr != 0;
        PermissionDialogDelegateJni.get()
                .acceptThisTime(mNativeDelegatePtr, PermissionDialogDelegate.this);
    }

    public void onCancel() {
        assert mNativeDelegatePtr != 0;
        PermissionDialogDelegateJni.get().cancel(mNativeDelegatePtr, PermissionDialogDelegate.this);
    }

    public void onDismiss(@DismissalType int dismissalType) {
        assert mNativeDelegatePtr != 0;
        PermissionDialogDelegateJni.get()
                .dismissed(mNativeDelegatePtr, PermissionDialogDelegate.this, dismissalType);
    }

    public void destroy() {
        assert mNativeDelegatePtr != 0;
        PermissionDialogDelegateJni.get()
                .destroy(mNativeDelegatePtr, PermissionDialogDelegate.this);
        mNativeDelegatePtr = 0;
    }

    public void setDialogController(PermissionDialogController controller) {
        mDialogController = controller;
    }

    /** Return the size of the RequestType enum used for permission requests. */
    public static int getRequestTypeEnumSize() {
        return PermissionDialogDelegateJni.get().getRequestTypeEnumSize();
    }

    /** Called from C++ by |nativeDelegatePtr| to destroy the dialog. */
    @CalledByNative
    private void dismissFromNative() {
        assert mDialogController != null;
        mDialogController.dismissFromNative(this);
    }

    @CalledByNative
    private void updateIcon(Bitmap icon) {
        assert mDialogController != null;
        mDialogController.updateIcon(icon);
    }

    @CalledByNative
    private int getIconSizeInPx() {
        assert mDialogController != null;
        return mDialogController.getIconSizeInPx();
    }

    /**
     * Called from C++ by |nativeDelegatePtr| to instantiate this class.
     *
     * @param nativeDelegatePtr The native counterpart that this object owns.
     * @param window The window to create the dialog for.
     * @param contentSettingsTypes The content settings types requested by this dialog.
     * @param iconId The id of the icon to display in the dialog.
     * @param message The message to display in the dialog.
     * @param boldedRanges A list of ranges (pairs of <textOffset, rangeSize>) that should be
     *     formatted as bold in the message.
     * @param positiveButtonText The text to display on the persistent grant button.
     * @param negativeButtonText The text to display on the persistent deny button.
     * @param positiveEphemeralButtonText The text to display on the ephemeral grant button. May be
     *     empty in which case only persistent grant and deny buttons are shown.
     */
    @CalledByNative
    private static PermissionDialogDelegate create(
            long nativeDelegatePtr,
            WindowAndroid window,
            int[] contentSettingsTypes,
            int iconId,
            String message,
            int[] boldedRanges,
            String positiveButtonText,
            String negativeButtonText,
            String positiveEphemeralButtonText,
            boolean showPositiveNonEphemeralAsFirstButton) {
        assert (boldedRanges.length % 2 == 0); // Contains a list of offset and length values

        return new PermissionDialogDelegate(
                nativeDelegatePtr,
                window,
                contentSettingsTypes,
                iconId,
                message,
                boldedRanges,
                positiveButtonText,
                negativeButtonText,
                positiveEphemeralButtonText,
                showPositiveNonEphemeralAsFirstButton);
    }

    /** Upon construction, this class takes ownership of the passed in native delegate. */
    private PermissionDialogDelegate(
            long nativeDelegatePtr,
            WindowAndroid window,
            int[] contentSettingsTypes,
            int iconId,
            String message,
            int[] boldedRanges,
            String positiveButtonText,
            String negativeButtonText,
            String positiveEphemeralButtonText,
            boolean showPositiveNonEphemeralAsFirstButton) {
        mNativeDelegatePtr = nativeDelegatePtr;
        mWindow = window;
        mContentSettingsTypes = contentSettingsTypes;
        mDrawableId = iconId;
        mMessageText = message;
        for (int i = 0; i + 1 < boldedRanges.length; i += 2) {
            mBoldedRanges.add(new Pair(boldedRanges[i], boldedRanges[i + 1]));
        }
        mPositiveButtonText = positiveButtonText;
        mNegativeButtonText = negativeButtonText;
        mPositiveEphemeralButtonText = positiveEphemeralButtonText;
        mShowPositiveNonEphemeralAsFirstButton = showPositiveNonEphemeralAsFirstButton;
    }

    @NativeMethods
    interface Natives {
        void accept(long nativePermissionDialogDelegate, PermissionDialogDelegate caller);

        void acceptThisTime(long nativePermissionDialogDelegate, PermissionDialogDelegate caller);

        void cancel(long nativePermissionDialogDelegate, PermissionDialogDelegate caller);

        void dismissed(
                long nativePermissionDialogDelegate,
                PermissionDialogDelegate caller,
                @DismissalType int dismissalType);

        void destroy(long nativePermissionDialogDelegate, PermissionDialogDelegate caller);

        int getRequestTypeEnumSize();
    }
}