chromium/chrome/android/java/src/org/chromium/chrome/browser/browserservices/permissiondelegation/InstalledWebappBridge.java

// Copyright 2019 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.chrome.browser.browserservices.permissiondelegation;

import android.net.Uri;

import org.jni_zero.CalledByNative;
import org.jni_zero.JniType;
import org.jni_zero.NativeMethods;

import org.chromium.components.content_settings.ContentSettingValues;
import org.chromium.components.content_settings.ContentSettingsType;
import org.chromium.components.embedder_support.util.Origin;

/**
 * Provides Trusted Web Activity Client App permissions for native. The C++ counterpart is the
 * {@code installed_webapp_bridge.h}.
 *
 * Lifecycle: All methods are static.
 * Thread safety: Methods will only be called on the UI thread.
 * Native: Requires native to be loaded.
 */
public class InstalledWebappBridge {
    private static long sNativeInstalledWebappProvider;

    /**
     * A POD class to store the combination of a permission setting and the origin the permission is
     * relevant for.
     *
     * It would make more sense for this to be a subclass of
     * {@link InstalledWebappPermissionManager} or a top level class. Unfortunately for the JNI
     * tool to be able to handle passing a class over the JNI boundary the class either needs to be
     * in this file or imported explicitly. Our presubmits don't like explicitly importing classes
     * that we don't need to, so it's easier to just let the class live here.
     */
    static class Permission {
        public final Origin origin;
        public final @ContentSettingValues int setting;

        public Permission(Origin origin, @ContentSettingValues int setting) {
            this.origin = origin;
            this.setting = setting;
        }
    }

    public static void notifyPermissionsChange(@ContentSettingsType.EnumType int type) {
        if (sNativeInstalledWebappProvider == 0) return;

        InstalledWebappBridgeJni.get()
                .notifyPermissionsChange(sNativeInstalledWebappProvider, type);
    }

    public static void runPermissionCallback(
            long callback, @ContentSettingValues int settingValue) {
        if (callback == 0) return;

        InstalledWebappBridgeJni.get().runPermissionCallback(callback, settingValue);
    }

    @CalledByNative
    private static void setInstalledWebappProvider(long provider) {
        sNativeInstalledWebappProvider = provider;
    }

    @CalledByNative
    private static Permission[] getPermissions(@ContentSettingsType.EnumType int type) {
        return InstalledWebappPermissionManager.get().getPermissions(type);
    }

    @CalledByNative
    private static @JniType("std::string") String getOriginFromPermission(Permission permission) {
        return permission.origin.toString();
    }

    @CalledByNative
    private static int getSettingFromPermission(Permission permission) {
        return permission.setting;
    }

    @CalledByNative
    private static void decidePermission(
            @ContentSettingsType.EnumType int type,
            @JniType("std::string") String originUrl,
            @JniType("std::string") String lastCommittedUrl,
            long callback) {
        Origin origin = Origin.create(Uri.parse(originUrl));
        if (origin == null) {
            runPermissionCallback(callback, ContentSettingValues.BLOCK);
            return;
        }
        switch (type) {
            case ContentSettingsType.GEOLOCATION:
                PermissionUpdater.get().getLocationPermission(origin, lastCommittedUrl, callback);
                break;
            case ContentSettingsType.NOTIFICATIONS:
                PermissionUpdater.get()
                        .requestNotificationPermission(origin, lastCommittedUrl, callback);
                break;
            default:
                throw new IllegalStateException("Unsupported permission type.");
        }
    }

    @NativeMethods
    interface Natives {
        void notifyPermissionsChange(long provider, int type);

        void runPermissionCallback(long callback, @ContentSettingValues int settingValue);
    }
}