GeolocationPermissions.java revision d875ce6dac3c2e9a671c121c80b40d2536cbb2af
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.concurrent.locks.Condition; 23import java.util.concurrent.locks.Lock; 24import java.util.concurrent.locks.ReentrantLock; 25import java.util.HashSet; 26import java.util.Set; 27 28 29/** 30 * Implements the Java side of GeolocationPermissions. Simply marshalls calls 31 * from the UI thread to the WebKit thread. 32 * @hide 33 */ 34public final class GeolocationPermissions { 35 /** 36 * Callback interface used by the browser to report a Geolocation permission 37 * state set by the user in response to a permissions prompt. 38 */ 39 public interface Callback { 40 public void invoke(String origin, boolean allow, boolean remember); 41 }; 42 43 // Log tag 44 private static final String TAG = "geolocationPermissions"; 45 46 // Global instance 47 private static GeolocationPermissions sInstance; 48 49 private Handler mHandler; 50 51 // Members used to transfer the origins and permissions between threads. 52 private Set<String> mOrigins; 53 private boolean mAllowed; 54 private Set<String> mOriginsToClear; 55 private Set<String> mOriginsToAllow; 56 private static Lock mLock = new ReentrantLock(); 57 private static boolean mUpdated; 58 private static Condition mUpdatedCondition = mLock.newCondition(); 59 60 // Message ids 61 static final int GET_ORIGINS = 0; 62 static final int GET_ALLOWED = 1; 63 static final int CLEAR = 2; 64 static final int ALLOW = 3; 65 static final int CLEAR_ALL = 4; 66 67 /** 68 * Gets the singleton instance of the class. 69 */ 70 public static GeolocationPermissions getInstance() { 71 if (sInstance == null) { 72 sInstance = new GeolocationPermissions(); 73 } 74 return sInstance; 75 } 76 77 /** 78 * Creates the message handler. Must be called on the WebKit thread. 79 */ 80 public void createHandler() { 81 mLock.lock(); 82 if (mHandler == null) { 83 mHandler = new Handler() { 84 @Override 85 public void handleMessage(Message msg) { 86 // Runs on the WebKit thread. 87 switch (msg.what) { 88 case GET_ORIGINS: 89 getOriginsImpl(); 90 break; 91 case GET_ALLOWED: 92 getAllowedImpl((String) msg.obj); 93 break; 94 case CLEAR: 95 nativeClear((String) msg.obj); 96 break; 97 case ALLOW: 98 nativeAllow((String) msg.obj); 99 break; 100 case CLEAR_ALL: 101 nativeClearAll(); 102 break; 103 } 104 } 105 }; 106 107 if (mOriginsToClear != null) { 108 for (String origin : mOriginsToClear) { 109 nativeClear(origin); 110 } 111 } 112 if (mOriginsToAllow != null) { 113 for (String origin : mOriginsToAllow) { 114 nativeAllow(origin); 115 } 116 } 117 } 118 mLock.unlock(); 119 } 120 121 /** 122 * Utility function to send a message to our handler. 123 */ 124 private void postMessage(Message msg) { 125 assert(mHandler != null); 126 mHandler.sendMessage(msg); 127 } 128 129 /** 130 * Gets the set of origins for which Geolocation permissions are stored. 131 * Note that we represent the origins as strings. These are created using 132 * WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules' 133 * (Database, Geolocation etc) do so, it's safe to match up origins for the 134 * purposes of displaying UI. 135 */ 136 public Set getOrigins() { 137 // Called on the UI thread. 138 Set origins = null; 139 mLock.lock(); 140 try { 141 mUpdated = false; 142 postMessage(Message.obtain(null, GET_ORIGINS)); 143 while (!mUpdated) { 144 mUpdatedCondition.await(); 145 } 146 origins = mOrigins; 147 } catch (InterruptedException e) { 148 Log.e(TAG, "Exception while waiting for update", e); 149 } finally { 150 mLock.unlock(); 151 } 152 return origins; 153 } 154 155 /** 156 * Helper method to get the set of origins. 157 */ 158 private void getOriginsImpl() { 159 // Called on the WebKit thread. 160 mLock.lock(); 161 mOrigins = nativeGetOrigins(); 162 mUpdated = true; 163 mUpdatedCondition.signal(); 164 mLock.unlock(); 165 } 166 167 /** 168 * Gets the permission state for the specified origin. 169 */ 170 public boolean getAllowed(String origin) { 171 // Called on the UI thread. 172 boolean allowed = false; 173 mLock.lock(); 174 try { 175 mUpdated = false; 176 postMessage(Message.obtain(null, GET_ALLOWED, origin)); 177 while (!mUpdated) { 178 mUpdatedCondition.await(); 179 } 180 allowed = mAllowed; 181 } catch (InterruptedException e) { 182 Log.e(TAG, "Exception while waiting for update", e); 183 } finally { 184 mLock.unlock(); 185 } 186 return allowed; 187 } 188 189 /** 190 * Helper method to get the permission state. 191 */ 192 private void getAllowedImpl(String origin) { 193 // Called on the WebKit thread. 194 mLock.lock(); 195 mAllowed = nativeGetAllowed(origin); 196 mUpdated = true; 197 mUpdatedCondition.signal(); 198 mLock.unlock(); 199 } 200 201 /** 202 * Clears the permission state for the specified origin. This method may be 203 * called before the WebKit thread has intialized the message handler. 204 * Messages will be queued until this time. 205 */ 206 public void clear(String origin) { 207 // Called on the UI thread. 208 mLock.lock(); 209 if (mHandler == null) { 210 if (mOriginsToClear == null) { 211 mOriginsToClear = new HashSet<String>(); 212 } 213 mOriginsToClear.add(origin); 214 if (mOriginsToAllow != null) { 215 mOriginsToAllow.remove(origin); 216 } 217 } else { 218 postMessage(Message.obtain(null, CLEAR, origin)); 219 } 220 mLock.unlock(); 221 } 222 223 /** 224 * Allows the specified origin. This method may be called before the WebKit 225 * thread has intialized the message handler. Messages will be queued until 226 * this time. 227 */ 228 public void allow(String origin) { 229 // Called on the UI thread. 230 mLock.lock(); 231 if (mHandler == null) { 232 if (mOriginsToAllow == null) { 233 mOriginsToAllow = new HashSet<String>(); 234 } 235 mOriginsToAllow.add(origin); 236 if (mOriginsToClear != null) { 237 mOriginsToClear.remove(origin); 238 } 239 } else { 240 postMessage(Message.obtain(null, ALLOW, origin)); 241 } 242 mLock.unlock(); 243 } 244 245 /** 246 * Clears the permission state for all origins. 247 */ 248 public void clearAll() { 249 // Called on the UI thread. 250 postMessage(Message.obtain(null, CLEAR_ALL)); 251 } 252 253 // Native functions, run on the WebKit thread. 254 private static native Set nativeGetOrigins(); 255 private static native boolean nativeGetAllowed(String origin); 256 private static native void nativeClear(String origin); 257 private static native void nativeAllow(String origin); 258 private static native void nativeClearAll(); 259} 260