chromium/android_webview/java/src/org/chromium/android_webview/AwGeolocationPermissions.java

// Copyright 2012 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;

import android.content.SharedPreferences;

import org.chromium.android_webview.common.Lifetime;
import org.chromium.net.GURLUtils;

import java.util.HashSet;
import java.util.Set;

/**
 * This class is used to manage permissions for the WebView's Geolocation JavaScript API.
 *
 * Callbacks are posted on the UI thread.
 */
@Lifetime.Profile
public final class AwGeolocationPermissions {
    private static final String PREF_PREFIX = "AwGeolocationPermissions%";
    private final SharedPreferences mSharedPreferences;

    /** See {@link android.webkit.GeolocationPermissions}. */
    public interface Callback {
        /* See {@link android.webkit.GeolocationPermissions}. */
        public void invoke(String origin, boolean allow, boolean retain);
    }

    public AwGeolocationPermissions(SharedPreferences sharedPreferences) {
        mSharedPreferences = sharedPreferences;
    }

    /** Set one origin to be allowed. */
    public void allow(String origin) {
        String key = getOriginKey(origin);
        if (key != null) {
            mSharedPreferences.edit().putBoolean(key, true).apply();
        }
    }

    /** Set one origin to be denied. */
    public void deny(String origin) {
        String key = getOriginKey(origin);
        if (key != null) {
            mSharedPreferences.edit().putBoolean(key, false).apply();
        }
    }

    /** Clear the stored permission for a particular origin. */
    public void clear(String origin) {
        String key = getOriginKey(origin);
        if (key != null) {
            mSharedPreferences.edit().remove(key).apply();
        }
    }

    /** Clear stored permissions for all origins. */
    public void clearAll() {
        SharedPreferences.Editor editor = null;
        for (String name : mSharedPreferences.getAll().keySet()) {
            if (name.startsWith(PREF_PREFIX)) {
                if (editor == null) {
                    editor = mSharedPreferences.edit();
                }
                editor.remove(name);
            }
        }
        if (editor != null) {
            editor.apply();
        }
    }

    /** Synchronous method to get if an origin is set to be allowed. */
    public boolean isOriginAllowed(String origin) {
        return mSharedPreferences.getBoolean(getOriginKey(origin), false);
    }

    /** Returns true if the origin is either set to allowed or denied. */
    public boolean hasOrigin(String origin) {
        return mSharedPreferences.contains(getOriginKey(origin));
    }

    /** Asynchronous method to get if an origin set to be allowed. */
    public void getAllowed(String origin, final org.chromium.base.Callback<Boolean> callback) {
        final boolean finalAllowed = isOriginAllowed(origin);
        AwThreadUtils.postToUiThreadLooper(callback.bind(finalAllowed));
    }

    /** Async method to get the domains currently allowed or denied. */
    public void getOrigins(final org.chromium.base.Callback<Set<String>> callback) {
        final Set<String> origins = new HashSet<String>();
        for (String name : mSharedPreferences.getAll().keySet()) {
            if (name.startsWith(PREF_PREFIX)) {
                origins.add(name.substring(PREF_PREFIX.length()));
            }
        }
        AwThreadUtils.postToUiThreadLooper(callback.bind(origins));
    }

    /** Get the domain of an URL using the GURL library. */
    private String getOriginKey(String url) {
        String origin = GURLUtils.getOrigin(url);
        if (origin.isEmpty()) {
            return null;
        }

        return PREF_PREFIX + origin;
    }

    /* package */
    static void migrateGeolocationPreferences(
            SharedPreferences oldPrefs, SharedPreferences newPrefs) {
        SharedPreferences.Editor oldPrefsEditor = oldPrefs.edit();

        SharedPreferences.Editor newPrefsEditor = newPrefs.edit();

        for (String name : oldPrefs.getAll().keySet()) {
            if (name.startsWith(AwGeolocationPermissions.PREF_PREFIX)) {
                newPrefsEditor.putBoolean(name, oldPrefs.getBoolean(name, false)).apply();
                oldPrefsEditor.remove(name).apply();
            }
        }
    }
}