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