1 /* 2 * Copyright (C) 2012 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 17 package android.webkit; 18 19 import android.os.Handler; 20 import android.os.Message; 21 22 import java.util.HashMap; 23 import java.util.Map; 24 import java.util.Set; 25 import java.util.Vector; 26 27 // This class is the Java counterpart of the WebKit C++ GeolocationPermissions 28 // class. It simply marshals calls from the UI thread to the WebKit thread. 29 final class GeolocationPermissionsClassic extends GeolocationPermissions { 30 private Handler mHandler; 31 private Handler mUIHandler; 32 33 // A queue to store messages until the handler is ready. 34 private Vector<Message> mQueuedMessages; 35 36 // Message ids 37 static final int GET_ORIGINS = 0; 38 static final int GET_ALLOWED = 1; 39 static final int CLEAR = 2; 40 static final int ALLOW = 3; 41 static final int CLEAR_ALL = 4; 42 43 // Message ids on the UI thread 44 static final int RETURN_ORIGINS = 0; 45 static final int RETURN_ALLOWED = 1; 46 47 private static final String ORIGINS = "origins"; 48 private static final String ORIGIN = "origin"; 49 private static final String CALLBACK = "callback"; 50 private static final String ALLOWED = "allowed"; 51 52 // Global instance 53 private static GeolocationPermissionsClassic sInstance; 54 getInstance()55 public static GeolocationPermissionsClassic getInstance() { 56 if (sInstance == null) { 57 sInstance = new GeolocationPermissionsClassic(); 58 } 59 return sInstance; 60 } 61 62 /** 63 * Creates the UI message handler. Must be called on the UI thread. 64 * @hide 65 */ createUIHandler()66 public void createUIHandler() { 67 if (mUIHandler == null) { 68 mUIHandler = new Handler() { 69 @Override 70 public void handleMessage(Message msg) { 71 // Runs on the UI thread. 72 switch (msg.what) { 73 case RETURN_ORIGINS: { 74 Map values = (Map) msg.obj; 75 Set<String> origins = (Set<String>) values.get(ORIGINS); 76 ValueCallback<Set<String> > callback = (ValueCallback<Set<String> >) values.get(CALLBACK); 77 callback.onReceiveValue(origins); 78 } break; 79 case RETURN_ALLOWED: { 80 Map values = (Map) msg.obj; 81 Boolean allowed = (Boolean) values.get(ALLOWED); 82 ValueCallback<Boolean> callback = (ValueCallback<Boolean>) values.get(CALLBACK); 83 callback.onReceiveValue(allowed); 84 } break; 85 } 86 } 87 }; 88 } 89 } 90 91 /** 92 * Creates the message handler. Must be called on the WebKit thread. 93 * @hide 94 */ createHandler()95 public synchronized void createHandler() { 96 if (mHandler == null) { 97 mHandler = new Handler() { 98 @Override 99 public void handleMessage(Message msg) { 100 // Runs on the WebKit thread. 101 switch (msg.what) { 102 case GET_ORIGINS: { 103 Set origins = nativeGetOrigins(); 104 ValueCallback callback = (ValueCallback) msg.obj; 105 Map values = new HashMap<String, Object>(); 106 values.put(CALLBACK, callback); 107 values.put(ORIGINS, origins); 108 postUIMessage(Message.obtain(null, RETURN_ORIGINS, values)); 109 } break; 110 case GET_ALLOWED: { 111 Map values = (Map) msg.obj; 112 String origin = (String) values.get(ORIGIN); 113 ValueCallback callback = (ValueCallback) values.get(CALLBACK); 114 boolean allowed = nativeGetAllowed(origin); 115 Map retValues = new HashMap<String, Object>(); 116 retValues.put(CALLBACK, callback); 117 retValues.put(ALLOWED, Boolean.valueOf(allowed)); 118 postUIMessage(Message.obtain(null, RETURN_ALLOWED, retValues)); 119 } break; 120 case CLEAR: 121 nativeClear((String) msg.obj); 122 break; 123 case ALLOW: 124 nativeAllow((String) msg.obj); 125 break; 126 case CLEAR_ALL: 127 nativeClearAll(); 128 break; 129 } 130 } 131 }; 132 133 // Handle the queued messages 134 if (mQueuedMessages != null) { 135 while (!mQueuedMessages.isEmpty()) { 136 mHandler.sendMessage(mQueuedMessages.remove(0)); 137 } 138 mQueuedMessages = null; 139 } 140 } 141 } 142 143 /** 144 * Utility function to send a message to our handler. 145 */ postMessage(Message msg)146 private synchronized void postMessage(Message msg) { 147 if (mHandler == null) { 148 if (mQueuedMessages == null) { 149 mQueuedMessages = new Vector<Message>(); 150 } 151 mQueuedMessages.add(msg); 152 } else { 153 mHandler.sendMessage(msg); 154 } 155 } 156 157 /** 158 * Utility function to send a message to the handler on the UI thread 159 */ postUIMessage(Message msg)160 private void postUIMessage(Message msg) { 161 if (mUIHandler != null) { 162 mUIHandler.sendMessage(msg); 163 } 164 } 165 166 // Note that we represent the origins as strings. These are created using 167 // WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules' 168 // (Database, Geolocation etc) do so, it's safe to match up origins based 169 // on this string. 170 @Override getOrigins(ValueCallback<Set<String> > callback)171 public void getOrigins(ValueCallback<Set<String> > callback) { 172 if (callback != null) { 173 if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) { 174 Set origins = nativeGetOrigins(); 175 callback.onReceiveValue(origins); 176 } else { 177 postMessage(Message.obtain(null, GET_ORIGINS, callback)); 178 } 179 } 180 } 181 182 @Override getAllowed(String origin, ValueCallback<Boolean> callback)183 public void getAllowed(String origin, ValueCallback<Boolean> callback) { 184 if (callback == null) { 185 return; 186 } 187 if (origin == null) { 188 callback.onReceiveValue(null); 189 return; 190 } 191 if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) { 192 boolean allowed = nativeGetAllowed(origin); 193 callback.onReceiveValue(Boolean.valueOf(allowed)); 194 } else { 195 Map values = new HashMap<String, Object>(); 196 values.put(ORIGIN, origin); 197 values.put(CALLBACK, callback); 198 postMessage(Message.obtain(null, GET_ALLOWED, values)); 199 } 200 } 201 202 // This method may be called before the WebKit 203 // thread has intialized the message handler. Messages will be queued until 204 // this time. 205 @Override clear(String origin)206 public void clear(String origin) { 207 // Called on the UI thread. 208 postMessage(Message.obtain(null, CLEAR, origin)); 209 } 210 211 // This method may be called before the WebKit 212 // thread has intialized the message handler. Messages will be queued until 213 // this time. 214 @Override allow(String origin)215 public void allow(String origin) { 216 // Called on the UI thread. 217 postMessage(Message.obtain(null, ALLOW, origin)); 218 } 219 220 @Override clearAll()221 public void clearAll() { 222 // Called on the UI thread. 223 postMessage(Message.obtain(null, CLEAR_ALL)); 224 } 225 GeolocationPermissionsClassic()226 GeolocationPermissionsClassic() {} 227 228 // Native functions, run on the WebKit thread. nativeGetOrigins()229 private static native Set nativeGetOrigins(); nativeGetAllowed(String origin)230 private static native boolean nativeGetAllowed(String origin); nativeClear(String origin)231 private static native void nativeClear(String origin); nativeAllow(String origin)232 private static native void nativeAllow(String origin); nativeClearAll()233 private static native void nativeClearAll(); 234 } 235