blob: a01541f66a93b41d66421f134914733d9c75e420 [file] [log] [blame]
Bjorn Bringerta7611812010-03-24 11:12:02 +00001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.browser;
18
19import android.content.Context;
20import android.content.SharedPreferences;
21import android.database.ContentObserver;
22import android.net.Uri;
23import android.os.AsyncTask;
24import android.os.Handler;
25import android.preference.PreferenceManager;
26import android.provider.Settings;
27import android.text.TextUtils;
28import android.webkit.GeolocationPermissions;
29import android.webkit.ValueCallback;
30
31import java.util.HashSet;
32import java.util.Set;
33
34/**
35 * Manages the interaction between the secure system setting for default geolocation
36 * permissions and the browser.
37 */
38class SystemAllowGeolocationOrigins {
39
40 // Preference key for the value of the system setting last read by the browser
41 private final static String LAST_READ_ALLOW_GEOLOCATION_ORIGINS =
42 "last_read_allow_geolocation_origins";
43
44 // The application context
45 private final Context mContext;
46
47 // The observer used to listen to the system setting.
48 private final SettingObserver mSettingObserver;
49
50 public SystemAllowGeolocationOrigins(Context context) {
51 mContext = context;
52 mSettingObserver = new SettingObserver();
53 }
54
55 /**
56 * Checks whether the setting has changed and installs an observer to listen for
57 * future changes. Must be called on the application main thread.
58 */
59 public void start() {
60 // Register to receive notifications when the system settings change.
61 Uri uri = Settings.Secure.getUriFor(Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS);
62 mContext.getContentResolver().registerContentObserver(uri, false, mSettingObserver);
63
64 // Read and apply the setting if needed.
65 maybeApplySettingAsync();
66 }
67
68 /**
69 * Stops the manager.
70 */
71 public void stop() {
72 mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
73 }
74
75 void maybeApplySettingAsync() {
John Reckcadae722011-07-25 11:36:17 -070076 BackgroundHandler.execute(mMaybeApplySetting);
Bjorn Bringerta7611812010-03-24 11:12:02 +000077 }
78
79 /**
80 * Checks to see if the system setting has changed and if so,
81 * updates the Geolocation permissions accordingly.
82 */
John Reckcadae722011-07-25 11:36:17 -070083 private Runnable mMaybeApplySetting = new Runnable() {
Bjorn Bringerta7611812010-03-24 11:12:02 +000084
John Reckcadae722011-07-25 11:36:17 -070085 @Override
86 public void run() {
87 // Get the new value
88 String newSetting = getSystemSetting();
Bjorn Bringerta7611812010-03-24 11:12:02 +000089
John Reckcadae722011-07-25 11:36:17 -070090 // Get the last read value
91 SharedPreferences preferences = BrowserSettings.getInstance()
92 .getPreferences();
93 String lastReadSetting =
94 preferences.getString(LAST_READ_ALLOW_GEOLOCATION_ORIGINS, "");
95
96 // If the new value is the same as the last one we read, we're done.
97 if (TextUtils.equals(lastReadSetting, newSetting)) {
98 return;
99 }
100
101 // Save the new value as the last read value
102 preferences.edit()
103 .putString(LAST_READ_ALLOW_GEOLOCATION_ORIGINS, newSetting)
104 .apply();
105
106 Set<String> oldOrigins = parseAllowGeolocationOrigins(lastReadSetting);
107 Set<String> newOrigins = parseAllowGeolocationOrigins(newSetting);
108 Set<String> addedOrigins = setMinus(newOrigins, oldOrigins);
109 Set<String> removedOrigins = setMinus(oldOrigins, newOrigins);
110
111 // Remove the origins in the last read value
112 removeOrigins(removedOrigins);
113
114 // Add the origins in the new value
115 addOrigins(addedOrigins);
Bjorn Bringerta7611812010-03-24 11:12:02 +0000116 }
John Reckcadae722011-07-25 11:36:17 -0700117 };
Bjorn Bringerta7611812010-03-24 11:12:02 +0000118
119 /**
120 * Parses the value of the default geolocation permissions setting.
121 *
122 * @param setting A space-separated list of origins.
123 * @return A mutable set of origins.
124 */
125 private static HashSet<String> parseAllowGeolocationOrigins(String setting) {
126 HashSet<String> origins = new HashSet<String>();
127 if (!TextUtils.isEmpty(setting)) {
128 for (String origin : setting.split("\\s+")) {
129 if (!TextUtils.isEmpty(origin)) {
130 origins.add(origin);
131 }
132 }
133 }
134 return origins;
135 }
136
137 /**
138 * Gets the difference between two sets. Does not modify any of the arguments.
139 *
140 * @return A set containing all elements in {@code x} that are not in {@code y}.
141 */
142 private <A> Set<A> setMinus(Set<A> x, Set<A> y) {
143 HashSet<A> z = new HashSet<A>(x.size());
144 for (A a : x) {
145 if (!y.contains(a)) {
146 z.add(a);
147 }
148 }
149 return z;
150 }
151
152 /**
153 * Gets the current system setting for default allowed geolocation origins.
154 *
155 * @return The default allowed origins. Returns {@code ""} if not set.
156 */
157 private String getSystemSetting() {
158 String value = Settings.Secure.getString(mContext.getContentResolver(),
159 Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS);
160 return value == null ? "" : value;
161 }
162
163 /**
164 * Adds geolocation permissions for the given origins.
165 */
166 private void addOrigins(Set<String> origins) {
167 for (String origin : origins) {
168 GeolocationPermissions.getInstance().allow(origin);
169 }
170 }
171
172 /**
173 * Removes geolocation permissions for the given origins, if they are allowed.
174 * If they are denied or not set, nothing is done.
175 */
176 private void removeOrigins(Set<String> origins) {
177 for (final String origin : origins) {
178 GeolocationPermissions.getInstance().getAllowed(origin, new ValueCallback<Boolean>() {
179 public void onReceiveValue(Boolean value) {
180 if (value != null && value.booleanValue()) {
181 GeolocationPermissions.getInstance().clear(origin);
182 }
183 }
184 });
185 }
186 }
187
188 /**
189 * Listens for changes to the system setting.
190 */
191 private class SettingObserver extends ContentObserver {
192
193 SettingObserver() {
194 super(new Handler());
195 }
196
197 @Override
198 public void onChange(boolean selfChange) {
199 maybeApplySettingAsync();
200 }
201 }
202
203}