1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.android_webview;
6 
7 import android.content.SharedPreferences;
8 
9 import org.chromium.net.GURLUtils;
10 
11 import java.util.HashSet;
12 import java.util.Set;
13 
14 /**
15  * This class is used to manage permissions for the WebView's Geolocation JavaScript API.
16  *
17  * Callbacks are posted on the UI thread.
18  */
19 public final class AwGeolocationPermissions {
20 
21     private static final String PREF_PREFIX =
22             "AwGeolocationPermissions%";
23     private final SharedPreferences mSharedPreferences;
24 
25     /** See {@link android.webkit.GeolocationPermissions}. */
26     public interface Callback {
27         /* See {@link android.webkit.GeolocationPermissions}. */
invoke(String origin, boolean allow, boolean retain)28         public void invoke(String origin, boolean allow, boolean retain);
29     }
30 
AwGeolocationPermissions(SharedPreferences sharedPreferences)31     public AwGeolocationPermissions(SharedPreferences sharedPreferences) {
32         mSharedPreferences = sharedPreferences;
33     }
34 
35     /**
36      * Set one origin to be allowed.
37      */
allow(String origin)38     public void allow(String origin) {
39         String key = getOriginKey(origin);
40         if (key != null) {
41             mSharedPreferences.edit().putBoolean(key, true).apply();
42         }
43     }
44 
45     /**
46      * Set one origin to be denied.
47      */
deny(String origin)48     public void deny(String origin) {
49         String key = getOriginKey(origin);
50         if (key != null) {
51             mSharedPreferences.edit().putBoolean(key, false).apply();
52         }
53     }
54 
55     /**
56      * Clear the stored permission for a particular origin.
57      */
clear(String origin)58     public void clear(String origin) {
59         String key = getOriginKey(origin);
60         if (key != null) {
61             mSharedPreferences.edit().remove(key).apply();
62         }
63     }
64 
65     /**
66      * Clear stored permissions for all origins.
67      */
clearAll()68     public void clearAll() {
69         SharedPreferences.Editor editor = null;
70         for (String name : mSharedPreferences.getAll().keySet()) {
71             if (name.startsWith(PREF_PREFIX)) {
72                 if (editor == null) {
73                     editor = mSharedPreferences.edit();
74                 }
75                 editor.remove(name);
76             }
77         }
78         if (editor != null) {
79             editor.apply();
80         }
81     }
82 
83     /**
84      * Synchronous method to get if an origin is set to be allowed.
85      */
isOriginAllowed(String origin)86     public boolean isOriginAllowed(String origin) {
87         return mSharedPreferences.getBoolean(getOriginKey(origin), false);
88     }
89 
90     /**
91      * Returns true if the origin is either set to allowed or denied.
92      */
hasOrigin(String origin)93     public boolean hasOrigin(String origin) {
94         return mSharedPreferences.contains(getOriginKey(origin));
95     }
96 
97     /**
98      * Asynchronous method to get if an origin set to be allowed.
99      */
getAllowed(String origin, final org.chromium.base.Callback<Boolean> callback)100     public void getAllowed(String origin, final org.chromium.base.Callback<Boolean> callback) {
101         final boolean finalAllowed = isOriginAllowed(origin);
102         AwThreadUtils.postToUiThreadLooper(callback.bind(finalAllowed));
103     }
104 
105     /**
106      * Async method to get the domains currently allowed or denied.
107      */
getOrigins(final org.chromium.base.Callback<Set<String>> callback)108     public void getOrigins(final org.chromium.base.Callback<Set<String>> callback) {
109         final Set<String> origins = new HashSet<String>();
110         for (String name : mSharedPreferences.getAll().keySet()) {
111             if (name.startsWith(PREF_PREFIX)) {
112                 origins.add(name.substring(PREF_PREFIX.length()));
113             }
114         }
115         AwThreadUtils.postToUiThreadLooper(callback.bind(origins));
116     }
117 
118     /**
119      * Get the domain of an URL using the GURL library.
120      */
getOriginKey(String url)121     private String getOriginKey(String url) {
122         String origin = GURLUtils.getOrigin(url);
123         if (origin.isEmpty()) {
124             return null;
125         }
126 
127         return PREF_PREFIX + origin;
128     }
129 
130     /* package */
migrateGeolocationPreferences( SharedPreferences oldPrefs, SharedPreferences newPrefs)131     static void migrateGeolocationPreferences(
132             SharedPreferences oldPrefs, SharedPreferences newPrefs) {
133         SharedPreferences.Editor oldPrefsEditor = oldPrefs.edit();
134 
135         SharedPreferences.Editor newPrefsEditor = newPrefs.edit();
136 
137         for (String name : oldPrefs.getAll().keySet()) {
138             if (name.startsWith(AwGeolocationPermissions.PREF_PREFIX)) {
139                 newPrefsEditor.putBoolean(name, oldPrefs.getBoolean(name, false)).apply();
140                 oldPrefsEditor.remove(name).apply();
141             }
142         }
143     }
144 }
145