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