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