GeolocationPermissions.java revision 939e5040b51539be561db1d18dec18196f201f5c
1/* 2 * Copyright (C) 2009 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 android.webkit; 18 19import android.os.Handler; 20import android.os.Message; 21 22import java.util.HashMap; 23import java.util.Map; 24import java.util.Set; 25import java.util.Vector; 26 27/** 28 * This class is used to manage permissions for the WebView's Geolocation 29 * JavaScript API. 30 * 31 * Geolocation permissions are applied to an origin, which consists of the 32 * host, scheme and port of a URI. In order for web content to use the 33 * Geolocation API, permission must be granted for that content's origin. 34 * 35 * This class stores Geolocation permissions. An origin's permission state can 36 * be either allowed or denied. This class uses Strings to represent 37 * an origin. 38 * 39 * When an origin attempts to use the Geolocation API, but no permission state 40 * is currently set for that origin, 41 * {@link WebChromeClient#onGeolocationPermissionsShowPrompt(String,GeolocationPermissions.Callback) WebChromeClient.onGeolocationPermissionsShowPrompt()} 42 * is called. This allows the permission state to be set for that origin. 43 * 44 * The methods of this class can be used to modify and interrogate the stored 45 * Geolocation permissions at any time. 46 */ 47// This class is the Java counterpart of the WebKit C++ GeolocationPermissions 48// class. It simply marshals calls from the UI thread to the WebKit thread. 49// 50// Within WebKit, Geolocation permissions may be applied either temporarily 51// (for the duration of the page) or permanently. This class deals only with 52// permanent permissions. 53public class GeolocationPermissions { 54 /** 55 * A callback interface used by the host application to set the Geolocation 56 * permission state for an origin. 57 */ 58 public interface Callback { 59 /** 60 * Set the Geolocation permission state for the supplied origin. 61 * @param origin The origin for which permissions are set. 62 * @param allow Whether or not the origin should be allowed to use the 63 * Geolocation API. 64 * @param retain Whether the permission should be retained beyond the 65 * lifetime of a page currently being displayed by a 66 * WebView. 67 */ 68 public void invoke(String origin, boolean allow, boolean retain); 69 }; 70 71 // Global instance 72 private static GeolocationPermissions sInstance; 73 74 private Handler mHandler; 75 private Handler mUIHandler; 76 77 // A queue to store messages until the handler is ready. 78 private Vector<Message> mQueuedMessages; 79 80 // Message ids 81 static final int GET_ORIGINS = 0; 82 static final int GET_ALLOWED = 1; 83 static final int CLEAR = 2; 84 static final int ALLOW = 3; 85 static final int CLEAR_ALL = 4; 86 87 // Message ids on the UI thread 88 static final int RETURN_ORIGINS = 0; 89 static final int RETURN_ALLOWED = 1; 90 91 private static final String ORIGINS = "origins"; 92 private static final String ORIGIN = "origin"; 93 private static final String CALLBACK = "callback"; 94 private static final String ALLOWED = "allowed"; 95 96 /** 97 * Get the singleton instance of this class. 98 * @return The singleton {@link GeolocationPermissions} instance. 99 */ 100 public static GeolocationPermissions getInstance() { 101 if (sInstance == null) { 102 sInstance = new GeolocationPermissions(); 103 } 104 return sInstance; 105 } 106 107 /** 108 * Creates the UI message handler. Must be called on the UI thread. 109 * @hide 110 */ 111 public void createUIHandler() { 112 if (mUIHandler == null) { 113 mUIHandler = new Handler() { 114 @Override 115 public void handleMessage(Message msg) { 116 // Runs on the UI thread. 117 switch (msg.what) { 118 case RETURN_ORIGINS: { 119 Map values = (Map) msg.obj; 120 Set<String> origins = (Set<String>) values.get(ORIGINS); 121 ValueCallback<Set<String> > callback = (ValueCallback<Set<String> >) values.get(CALLBACK); 122 callback.onReceiveValue(origins); 123 } break; 124 case RETURN_ALLOWED: { 125 Map values = (Map) msg.obj; 126 Boolean allowed = (Boolean) values.get(ALLOWED); 127 ValueCallback<Boolean> callback = (ValueCallback<Boolean>) values.get(CALLBACK); 128 callback.onReceiveValue(allowed); 129 } break; 130 } 131 } 132 }; 133 } 134 } 135 136 /** 137 * Creates the message handler. Must be called on the WebKit thread. 138 * @hide 139 */ 140 public synchronized void createHandler() { 141 if (mHandler == null) { 142 mHandler = new Handler() { 143 @Override 144 public void handleMessage(Message msg) { 145 // Runs on the WebKit thread. 146 switch (msg.what) { 147 case GET_ORIGINS: { 148 Set origins = nativeGetOrigins(); 149 ValueCallback callback = (ValueCallback) msg.obj; 150 Map values = new HashMap<String, Object>(); 151 values.put(CALLBACK, callback); 152 values.put(ORIGINS, origins); 153 postUIMessage(Message.obtain(null, RETURN_ORIGINS, values)); 154 } break; 155 case GET_ALLOWED: { 156 Map values = (Map) msg.obj; 157 String origin = (String) values.get(ORIGIN); 158 ValueCallback callback = (ValueCallback) values.get(CALLBACK); 159 boolean allowed = nativeGetAllowed(origin); 160 Map retValues = new HashMap<String, Object>(); 161 retValues.put(CALLBACK, callback); 162 retValues.put(ALLOWED, Boolean.valueOf(allowed)); 163 postUIMessage(Message.obtain(null, RETURN_ALLOWED, retValues)); 164 } break; 165 case CLEAR: 166 nativeClear((String) msg.obj); 167 break; 168 case ALLOW: 169 nativeAllow((String) msg.obj); 170 break; 171 case CLEAR_ALL: 172 nativeClearAll(); 173 break; 174 } 175 } 176 }; 177 178 // Handle the queued messages 179 if (mQueuedMessages != null) { 180 while (!mQueuedMessages.isEmpty()) { 181 mHandler.sendMessage(mQueuedMessages.remove(0)); 182 } 183 mQueuedMessages = null; 184 } 185 } 186 } 187 188 /** 189 * Utility function to send a message to our handler. 190 */ 191 private synchronized void postMessage(Message msg) { 192 if (mHandler == null) { 193 if (mQueuedMessages == null) { 194 mQueuedMessages = new Vector<Message>(); 195 } 196 mQueuedMessages.add(msg); 197 } else { 198 mHandler.sendMessage(msg); 199 } 200 } 201 202 /** 203 * Utility function to send a message to the handler on the UI thread 204 */ 205 private void postUIMessage(Message msg) { 206 if (mUIHandler != null) { 207 mUIHandler.sendMessage(msg); 208 } 209 } 210 211 /** 212 * Get the set of origins for which Geolocation permissions are stored. 213 * @param callback A {@link ValueCallback} to receive the result of this 214 * request. This object's 215 * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} 216 * method will be invoked asynchronously with a set of 217 * Strings containing the origins for which Geolocation 218 * permissions are stored. 219 */ 220 // Note that we represent the origins as strings. These are created using 221 // WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules' 222 // (Database, Geolocation etc) do so, it's safe to match up origins based 223 // on this string. 224 public void getOrigins(ValueCallback<Set<String> > callback) { 225 if (callback != null) { 226 if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) { 227 Set origins = nativeGetOrigins(); 228 callback.onReceiveValue(origins); 229 } else { 230 postMessage(Message.obtain(null, GET_ORIGINS, callback)); 231 } 232 } 233 } 234 235 /** 236 * Get the Geolocation permission state for the specified origin. 237 * @param origin The origin for which Geolocation permission is requested. 238 * @param callback A {@link ValueCallback} to receive the result of this 239 * request. This object's 240 * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} 241 * method will be invoked asynchronously with a boolean 242 * indicating whether or not the origin can use the 243 * Geolocation API. 244 */ 245 public void getAllowed(String origin, ValueCallback<Boolean> callback) { 246 if (callback == null) { 247 return; 248 } 249 if (origin == null) { 250 callback.onReceiveValue(null); 251 return; 252 } 253 if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) { 254 boolean allowed = nativeGetAllowed(origin); 255 callback.onReceiveValue(new Boolean(allowed)); 256 } else { 257 Map values = new HashMap<String, Object>(); 258 values.put(ORIGIN, origin); 259 values.put(CALLBACK, callback); 260 postMessage(Message.obtain(null, GET_ALLOWED, values)); 261 } 262 } 263 264 /** 265 * Clear the Geolocation permission state for the specified origin. 266 * @param origin The origin for which Geolocation permissions are cleared. 267 */ 268 // This method may be called before the WebKit 269 // thread has intialized the message handler. Messages will be queued until 270 // this time. 271 public void clear(String origin) { 272 // Called on the UI thread. 273 postMessage(Message.obtain(null, CLEAR, origin)); 274 } 275 276 /** 277 * Allow the specified origin to use the Geolocation API. 278 * @param origin The origin for which Geolocation API use is allowed. 279 */ 280 // This method may be called before the WebKit 281 // thread has intialized the message handler. Messages will be queued until 282 // this time. 283 public void allow(String origin) { 284 // Called on the UI thread. 285 postMessage(Message.obtain(null, ALLOW, origin)); 286 } 287 288 /** 289 * Clear the Geolocation permission state for all origins. 290 */ 291 public void clearAll() { 292 // Called on the UI thread. 293 postMessage(Message.obtain(null, CLEAR_ALL)); 294 } 295 296 /** 297 * This class should not be instantiated directly, applications must only use 298 * {@link #getInstance()} to obtain the instance. 299 * Note this constructor was erroneously public and published in SDK levels prior to 16, but 300 * applications using it would receive a non-functional instance of this class (there was no 301 * way to call createHandler() and createUIHandler(), so it would not work). 302 * @hide 303 */ 304 public GeolocationPermissions() {} 305 306 // Native functions, run on the WebKit thread. 307 private static native Set nativeGetOrigins(); 308 private static native boolean nativeGetAllowed(String origin); 309 private static native void nativeClear(String origin); 310 private static native void nativeAllow(String origin); 311 private static native void nativeClearAll(); 312} 313