chromium/android_webview/java/src/org/chromium/android_webview/permission/AwPermissionRequest.java

// Copyright 2014 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.android_webview.permission;

import android.net.Uri;

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

import org.chromium.android_webview.CleanupReference;
import org.chromium.android_webview.common.Lifetime;
import org.chromium.base.ThreadUtils;

/**
 * This class wraps permission request in Chromium side, and can only be created
 * by native side.
 */
@Lifetime.Temporary
@JNINamespace("android_webview")
public class AwPermissionRequest {
    private final Uri mOrigin;
    private final long mResources;
    private boolean mProcessed;

    // AwPermissionRequest native instance.
    private long mNativeAwPermissionRequest;

    // Responsible for deleting native peer.
    private CleanupReference mCleanupReference;

    private static final class DestroyRunnable implements Runnable {
        private final long mNativeAwPermissionRequest;

        private DestroyRunnable(long nativeAwPermissionRequest) {
            mNativeAwPermissionRequest = nativeAwPermissionRequest;
        }

        @Override
        public void run() {
            AwPermissionRequestJni.get().destroy(mNativeAwPermissionRequest);
        }
    }

    @CalledByNative
    private static AwPermissionRequest create(
            long nativeAwPermissionRequest, String url, long resources) {
        if (nativeAwPermissionRequest == 0) return null;
        Uri origin = Uri.parse(url);
        return new AwPermissionRequest(nativeAwPermissionRequest, origin, resources);
    }

    private AwPermissionRequest(long nativeAwPermissionRequest, Uri origin, long resources) {
        mNativeAwPermissionRequest = nativeAwPermissionRequest;
        mOrigin = origin;
        mResources = resources;
        mCleanupReference =
                new CleanupReference(this, new DestroyRunnable(mNativeAwPermissionRequest));
    }

    public Uri getOrigin() {
        return mOrigin;
    }

    public long getResources() {
        return mResources;
    }

    public void grant() {
        validate();
        if (mNativeAwPermissionRequest != 0) {
            AwPermissionRequestJni.get()
                    .onAccept(mNativeAwPermissionRequest, AwPermissionRequest.this, true);
            destroyNative();
        }
        mProcessed = true;
    }

    public void deny() {
        validate();
        if (mNativeAwPermissionRequest != 0) {
            AwPermissionRequestJni.get()
                    .onAccept(mNativeAwPermissionRequest, AwPermissionRequest.this, false);
            destroyNative();
        }
        mProcessed = true;
    }

    @CalledByNative
    private void destroyNative() {
        mCleanupReference.cleanupNow();
        mCleanupReference = null;
        mNativeAwPermissionRequest = 0;
    }

    private void validate() {
        if (!ThreadUtils.runningOnUiThread()) {
            throw new IllegalStateException(
                    "Either grant() or deny() should be called on UI thread");
        }

        if (mProcessed) {
            throw new IllegalStateException("Either grant() or deny() has been already called.");
        }
    }

    @NativeMethods
    interface Natives {
        void onAccept(long nativeAwPermissionRequest, AwPermissionRequest caller, boolean allowed);

        void destroy(long nativeAwPermissionRequest);
    }
}