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