Home | History | Annotate | Download | only in webkit
      1 /*
      2  * Copyright (C) 2006 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.net.ProxyProperties;
     20 import android.net.Uri;
     21 import android.os.Handler;
     22 import android.os.Message;
     23 import android.util.Log;
     24 
     25 import java.lang.ref.WeakReference;
     26 import java.util.HashMap;
     27 import java.util.Set;
     28 
     29 final class JWebCoreJavaBridge extends Handler {
     30     // Identifier for the timer message.
     31     private static final int TIMER_MESSAGE = 1;
     32     // ID for servicing functionptr queue
     33     private static final int FUNCPTR_MESSAGE = 2;
     34     // Log system identifier.
     35     private static final String LOGTAG = "webkit-timers";
     36 
     37     // Native object pointer for interacting in native code.
     38     private int mNativeBridge;
     39     // Instant timer is used to implement a timer that needs to fire almost
     40     // immediately.
     41     private boolean mHasInstantTimer;
     42 
     43     private boolean mTimerPaused;
     44     private boolean mHasDeferredTimers;
     45 
     46     // keep track of the main WebView attached to the current window so that we
     47     // can get the proper Context.
     48     private static WeakReference<WebView> sCurrentMainWebView =
     49             new WeakReference<WebView>(null);
     50 
     51     /* package */
     52     static final int REFRESH_PLUGINS = 100;
     53 
     54     private HashMap<String, String> mContentUriToFilePathMap;
     55 
     56     /**
     57      * Construct a new JWebCoreJavaBridge to interface with
     58      * WebCore timers and cookies.
     59      */
     60     public JWebCoreJavaBridge() {
     61         nativeConstructor();
     62 
     63     }
     64 
     65     @Override
     66     protected void finalize() {
     67         nativeFinalize();
     68     }
     69 
     70     static synchronized void setActiveWebView(WebView webview) {
     71         if (sCurrentMainWebView.get() != null) {
     72             // it is possible if there is a sub-WebView. Do nothing.
     73             return;
     74         }
     75         sCurrentMainWebView = new WeakReference<WebView>(webview);
     76     }
     77 
     78     static synchronized void removeActiveWebView(WebView webview) {
     79         if (sCurrentMainWebView.get() != webview) {
     80             // it is possible if there is a sub-WebView. Do nothing.
     81             return;
     82         }
     83         sCurrentMainWebView.clear();
     84     }
     85 
     86     /**
     87      * Call native timer callbacks.
     88      */
     89     private void fireSharedTimer() {
     90         // clear the flag so that sharedTimerFired() can set a new timer
     91         mHasInstantTimer = false;
     92         sharedTimerFired();
     93     }
     94 
     95     /**
     96      * handleMessage
     97      * @param msg The dispatched message.
     98      *
     99      * The only accepted message currently is TIMER_MESSAGE
    100      */
    101     @Override
    102     public void handleMessage(Message msg) {
    103         switch (msg.what) {
    104             case TIMER_MESSAGE: {
    105                 if (mTimerPaused) {
    106                     mHasDeferredTimers = true;
    107                 } else {
    108                     fireSharedTimer();
    109                 }
    110                 break;
    111             }
    112             case FUNCPTR_MESSAGE:
    113                 nativeServiceFuncPtrQueue();
    114                 break;
    115             case REFRESH_PLUGINS:
    116                 nativeUpdatePluginDirectories(PluginManager.getInstance(null)
    117                         .getPluginDirectories(), ((Boolean) msg.obj)
    118                         .booleanValue());
    119                 break;
    120         }
    121     }
    122 
    123     // called from JNI side
    124     private void signalServiceFuncPtrQueue() {
    125         Message msg = obtainMessage(FUNCPTR_MESSAGE);
    126         sendMessage(msg);
    127     }
    128 
    129     private native void nativeServiceFuncPtrQueue();
    130 
    131     /**
    132      * Pause all timers.
    133      */
    134     public void pause() {
    135         if (!mTimerPaused) {
    136             mTimerPaused = true;
    137             mHasDeferredTimers = false;
    138         }
    139     }
    140 
    141     /**
    142      * Resume all timers.
    143      */
    144     public void resume() {
    145         if (mTimerPaused) {
    146            mTimerPaused = false;
    147            if (mHasDeferredTimers) {
    148                mHasDeferredTimers = false;
    149                fireSharedTimer();
    150            }
    151         }
    152     }
    153 
    154     /**
    155      * Set WebCore cache size.
    156      * @param bytes The cache size in bytes.
    157      */
    158     public native void setCacheSize(int bytes);
    159 
    160     /**
    161      * Store a cookie string associated with a url.
    162      * @param url The url to be used as a key for the cookie.
    163      * @param value The cookie string to be stored.
    164      */
    165     private void setCookies(String url, String value) {
    166         if (value.contains("\r") || value.contains("\n")) {
    167             // for security reason, filter out '\r' and '\n' from the cookie
    168             int size = value.length();
    169             StringBuilder buffer = new StringBuilder(size);
    170             int i = 0;
    171             while (i != -1 && i < size) {
    172                 int ir = value.indexOf('\r', i);
    173                 int in = value.indexOf('\n', i);
    174                 int newi = (ir == -1) ? in : (in == -1 ? ir : (ir < in ? ir
    175                         : in));
    176                 if (newi > i) {
    177                     buffer.append(value.subSequence(i, newi));
    178                 } else if (newi == -1) {
    179                     buffer.append(value.subSequence(i, size));
    180                     break;
    181                 }
    182                 i = newi + 1;
    183             }
    184             value = buffer.toString();
    185         }
    186         CookieManager.getInstance().setCookie(url, value);
    187     }
    188 
    189     /**
    190      * Retrieve the cookie string for the given url.
    191      * @param url The resource's url.
    192      * @return A String representing the cookies for the given resource url.
    193      */
    194     private String cookies(String url) {
    195         return CookieManager.getInstance().getCookie(url);
    196     }
    197 
    198     /**
    199      * Returns whether cookies are enabled or not.
    200      */
    201     private boolean cookiesEnabled() {
    202         return CookieManager.getInstance().acceptCookie();
    203     }
    204 
    205     /**
    206      * Returns an array of plugin directoies
    207      */
    208     private String[] getPluginDirectories() {
    209         return PluginManager.getInstance(null).getPluginDirectories();
    210     }
    211 
    212     /**
    213      * Returns the path of the plugin data directory
    214      */
    215     private String getPluginSharedDataDirectory() {
    216         return PluginManager.getInstance(null).getPluginSharedDataDirectory();
    217     }
    218 
    219     /**
    220      * setSharedTimer
    221      * @param timemillis The relative time when the timer should fire
    222      */
    223     private void setSharedTimer(long timemillis) {
    224         if (DebugFlags.J_WEB_CORE_JAVA_BRIDGE) Log.v(LOGTAG, "setSharedTimer " + timemillis);
    225 
    226         if (timemillis <= 0) {
    227             // we don't accumulate the sharedTimer unless it is a delayed
    228             // request. This way we won't flood the message queue with
    229             // WebKit messages. This should improve the browser's
    230             // responsiveness to key events.
    231             if (mHasInstantTimer) {
    232                 return;
    233             } else {
    234                 mHasInstantTimer = true;
    235                 Message msg = obtainMessage(TIMER_MESSAGE);
    236                 sendMessageDelayed(msg, timemillis);
    237             }
    238         } else {
    239             Message msg = obtainMessage(TIMER_MESSAGE);
    240             sendMessageDelayed(msg, timemillis);
    241         }
    242     }
    243 
    244     /**
    245      * Stop the shared timer.
    246      */
    247     private void stopSharedTimer() {
    248         if (DebugFlags.J_WEB_CORE_JAVA_BRIDGE) {
    249             Log.v(LOGTAG, "stopSharedTimer removing all timers");
    250         }
    251         removeMessages(TIMER_MESSAGE);
    252         mHasInstantTimer = false;
    253         mHasDeferredTimers = false;
    254     }
    255 
    256     private String[] getKeyStrengthList() {
    257         return CertTool.getKeyStrengthList();
    258     }
    259 
    260     synchronized private String getSignedPublicKey(int index, String challenge,
    261             String url) {
    262         WebView current = sCurrentMainWebView.get();
    263         if (current != null) {
    264             // generateKeyPair expects organizations which we don't have. Ignore
    265             // url.
    266             return CertTool.getSignedPublicKey(
    267                     current.getContext(), index, challenge);
    268         } else {
    269             Log.e(LOGTAG, "There is no active WebView for getSignedPublicKey");
    270             return "";
    271         }
    272     }
    273 
    274     // Called on the WebCore thread through JNI.
    275     private String resolveFilePathForContentUri(String uri) {
    276         if (mContentUriToFilePathMap != null) {
    277             String fileName = mContentUriToFilePathMap.get(uri);
    278             if (fileName != null) {
    279                 return fileName;
    280             }
    281         }
    282 
    283         // Failsafe fallback to just use the last path segment.
    284         // (See OpenableColumns documentation in the SDK)
    285         Uri jUri = Uri.parse(uri);
    286         return jUri.getLastPathSegment();
    287     }
    288 
    289     public void storeFilePathForContentUri(String path, String contentUri) {
    290         if (mContentUriToFilePathMap == null) {
    291             mContentUriToFilePathMap = new HashMap<String, String>();
    292         }
    293         mContentUriToFilePathMap.put(contentUri, path);
    294     }
    295 
    296     public void updateProxy(ProxyProperties proxyProperties) {
    297         if (proxyProperties == null) {
    298             nativeUpdateProxy("", "");
    299             return;
    300         }
    301 
    302         String host = proxyProperties.getHost();
    303         int port = proxyProperties.getPort();
    304         if (port != 0)
    305             host += ":" + port;
    306 
    307         nativeUpdateProxy(host, proxyProperties.getExclusionList());
    308     }
    309 
    310     private native void nativeConstructor();
    311     private native void nativeFinalize();
    312     private native void sharedTimerFired();
    313     private native void nativeUpdatePluginDirectories(String[] directories,
    314             boolean reload);
    315     public native void setNetworkOnLine(boolean online);
    316     public native void setNetworkType(String type, String subtype);
    317     public native void addPackageNames(Set<String> packageNames);
    318     public native void addPackageName(String packageName);
    319     public native void removePackageName(String packageName);
    320     public native void nativeUpdateProxy(String newProxy, String exclusionList);
    321 }
    322