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