Home | History | Annotate | Download | only in webkit
      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 
     17 package android.webkit;
     18 
     19 import android.os.Handler;
     20 import android.os.Message;
     21 import android.util.Log;
     22 import java.util.HashMap;
     23 import java.util.HashSet;
     24 import java.util.Map;
     25 import java.util.Set;
     26 import java.util.Vector;
     27 
     28 
     29 /**
     30  * This class is used to get Geolocation permissions from, and set them on the
     31  * WebView. For example, it could be used to allow a user to manage Geolocation
     32  * permissions from a browser's UI.
     33  *
     34  * Permissions are managed on a per-origin basis, as required by the
     35  * Geolocation spec - http://dev.w3.org/geo/api/spec-source.html. An origin
     36  * specifies the scheme, host and port of particular frame. An origin is
     37  * represented here as a string, using the output of
     38  * WebCore::SecurityOrigin::toString.
     39  *
     40  * This class is the Java counterpart of the WebKit C++ GeolocationPermissions
     41  * class. It simply marshalls calls from the UI thread to the WebKit thread.
     42  *
     43  * Within WebKit, Geolocation permissions may be applied either temporarily
     44  * (for the duration of the page) or permanently. This class deals only with
     45  * permanent permissions.
     46  */
     47 public final class GeolocationPermissions {
     48     /**
     49      * Callback interface used by the browser to report a Geolocation permission
     50      * state set by the user in response to a permissions prompt.
     51      */
     52     public interface Callback {
     53         public void invoke(String origin, boolean allow, boolean remember);
     54     };
     55 
     56     // Log tag
     57     private static final String TAG = "geolocationPermissions";
     58 
     59     // Global instance
     60     private static GeolocationPermissions sInstance;
     61 
     62     private Handler mHandler;
     63     private Handler mUIHandler;
     64 
     65     // A queue to store messages until the handler is ready.
     66     private Vector<Message> mQueuedMessages;
     67 
     68     // Message ids
     69     static final int GET_ORIGINS = 0;
     70     static final int GET_ALLOWED = 1;
     71     static final int CLEAR = 2;
     72     static final int ALLOW = 3;
     73     static final int CLEAR_ALL = 4;
     74 
     75     // Message ids on the UI thread
     76     static final int RETURN_ORIGINS = 0;
     77     static final int RETURN_ALLOWED = 1;
     78 
     79     private static final String ORIGINS = "origins";
     80     private static final String ORIGIN = "origin";
     81     private static final String CALLBACK = "callback";
     82     private static final String ALLOWED = "allowed";
     83 
     84     /**
     85      * Gets the singleton instance of the class.
     86      */
     87     public static GeolocationPermissions getInstance() {
     88       if (sInstance == null) {
     89           sInstance = new GeolocationPermissions();
     90       }
     91       return sInstance;
     92     }
     93 
     94     /**
     95      * Creates the UI message handler. Must be called on the UI thread.
     96      * @hide
     97      */
     98     public void createUIHandler() {
     99         if (mUIHandler == null) {
    100             mUIHandler = new Handler() {
    101                 @Override
    102                 public void handleMessage(Message msg) {
    103                     // Runs on the UI thread.
    104                     switch (msg.what) {
    105                         case RETURN_ORIGINS: {
    106                             Map values = (Map) msg.obj;
    107                             Set<String> origins = (Set<String>) values.get(ORIGINS);
    108                             ValueCallback<Set<String> > callback = (ValueCallback<Set<String> >) values.get(CALLBACK);
    109                             callback.onReceiveValue(origins);
    110                         } break;
    111                         case RETURN_ALLOWED: {
    112                             Map values = (Map) msg.obj;
    113                             Boolean allowed = (Boolean) values.get(ALLOWED);
    114                             ValueCallback<Boolean> callback = (ValueCallback<Boolean>) values.get(CALLBACK);
    115                             callback.onReceiveValue(allowed);
    116                         } break;
    117                     }
    118                 }
    119             };
    120         }
    121     }
    122 
    123     /**
    124      * Creates the message handler. Must be called on the WebKit thread.
    125      * @hide
    126      */
    127     public synchronized void createHandler() {
    128         if (mHandler == null) {
    129             mHandler = new Handler() {
    130                 @Override
    131                 public void handleMessage(Message msg) {
    132                     // Runs on the WebKit thread.
    133                     switch (msg.what) {
    134                         case GET_ORIGINS: {
    135                             Set origins = nativeGetOrigins();
    136                             ValueCallback callback = (ValueCallback) msg.obj;
    137                             Map values = new HashMap<String, Object>();
    138                             values.put(CALLBACK, callback);
    139                             values.put(ORIGINS, origins);
    140                             postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
    141                             } break;
    142                         case GET_ALLOWED: {
    143                             Map values = (Map) msg.obj;
    144                             String origin = (String) values.get(ORIGIN);
    145                             ValueCallback callback = (ValueCallback) values.get(CALLBACK);
    146                             boolean allowed = nativeGetAllowed(origin);
    147                             Map retValues = new HashMap<String, Object>();
    148                             retValues.put(CALLBACK, callback);
    149                             retValues.put(ALLOWED, new Boolean(allowed));
    150                             postUIMessage(Message.obtain(null, RETURN_ALLOWED, retValues));
    151                             } break;
    152                         case CLEAR:
    153                             nativeClear((String) msg.obj);
    154                             break;
    155                         case ALLOW:
    156                             nativeAllow((String) msg.obj);
    157                             break;
    158                         case CLEAR_ALL:
    159                             nativeClearAll();
    160                             break;
    161                     }
    162                 }
    163             };
    164 
    165             // Handle the queued messages
    166             if (mQueuedMessages != null) {
    167                 while (!mQueuedMessages.isEmpty()) {
    168                     mHandler.sendMessage(mQueuedMessages.remove(0));
    169                 }
    170                 mQueuedMessages = null;
    171             }
    172         }
    173     }
    174 
    175     /**
    176      * Utility function to send a message to our handler.
    177      */
    178     private synchronized void postMessage(Message msg) {
    179         if (mHandler == null) {
    180             if (mQueuedMessages == null) {
    181                 mQueuedMessages = new Vector<Message>();
    182             }
    183             mQueuedMessages.add(msg);
    184         } else {
    185             mHandler.sendMessage(msg);
    186         }
    187     }
    188 
    189     /**
    190      * Utility function to send a message to the handler on the UI thread
    191      */
    192     private void postUIMessage(Message msg) {
    193         if (mUIHandler != null) {
    194             mUIHandler.sendMessage(msg);
    195         }
    196     }
    197 
    198     /**
    199      * Gets the set of origins for which Geolocation permissions are stored.
    200      * Note that we represent the origins as strings. These are created using
    201      * WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules'
    202      * (Database, Geolocation etc) do so, it's safe to match up origins based
    203      * on this string.
    204      *
    205      * Callback is a ValueCallback object whose onReceiveValue method will be
    206      * called asynchronously with the set of origins.
    207      */
    208     public void getOrigins(ValueCallback<Set<String> > callback) {
    209         if (callback != null) {
    210             if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
    211                 Set origins = nativeGetOrigins();
    212                 callback.onReceiveValue(origins);
    213             } else {
    214                 postMessage(Message.obtain(null, GET_ORIGINS, callback));
    215             }
    216         }
    217     }
    218 
    219     /**
    220      * Gets the permission state for the specified origin.
    221      *
    222      * Callback is a ValueCallback object whose onReceiveValue method will be
    223      * called asynchronously with the permission state for the origin.
    224      */
    225     public void getAllowed(String origin, ValueCallback<Boolean> callback) {
    226         if (callback == null) {
    227             return;
    228         }
    229         if (origin == null) {
    230             callback.onReceiveValue(null);
    231             return;
    232         }
    233         if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
    234             boolean allowed = nativeGetAllowed(origin);
    235             callback.onReceiveValue(new Boolean(allowed));
    236         } else {
    237             Map values = new HashMap<String, Object>();
    238             values.put(ORIGIN, origin);
    239             values.put(CALLBACK, callback);
    240             postMessage(Message.obtain(null, GET_ALLOWED, values));
    241         }
    242     }
    243 
    244     /**
    245      * Clears the permission state for the specified origin. This method may be
    246      * called before the WebKit thread has intialized the message handler.
    247      * Messages will be queued until this time.
    248      */
    249     public void clear(String origin) {
    250         // Called on the UI thread.
    251         postMessage(Message.obtain(null, CLEAR, origin));
    252     }
    253 
    254     /**
    255      * Allows the specified origin. This method may be called before the WebKit
    256      * thread has intialized the message handler. Messages will be queued until
    257      * this time.
    258      */
    259     public void allow(String origin) {
    260         // Called on the UI thread.
    261         postMessage(Message.obtain(null, ALLOW, origin));
    262     }
    263 
    264     /**
    265      * Clears the permission state for all origins.
    266      */
    267     public void clearAll() {
    268         // Called on the UI thread.
    269         postMessage(Message.obtain(null, CLEAR_ALL));
    270     }
    271 
    272     // Native functions, run on the WebKit thread.
    273     private static native Set nativeGetOrigins();
    274     private static native boolean nativeGetAllowed(String origin);
    275     private static native void nativeClear(String origin);
    276     private static native void nativeAllow(String origin);
    277     private static native void nativeClearAll();
    278 }
    279