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.os.Handler; 20 import android.os.Message; 21 import android.util.Log; 22 23 import java.lang.ref.WeakReference; 24 import java.util.HashMap; 25 import java.util.Set; 26 27 final class JWebCoreJavaBridge extends Handler { 28 // Identifier for the timer message. 29 private static final int TIMER_MESSAGE = 1; 30 // ID for servicing functionptr queue 31 private static final int FUNCPTR_MESSAGE = 2; 32 // Log system identifier. 33 private static final String LOGTAG = "webkit-timers"; 34 35 // Native object pointer for interacting in native code. 36 private int mNativeBridge; 37 // Instant timer is used to implement a timer that needs to fire almost 38 // immediately. 39 private boolean mHasInstantTimer; 40 41 // Reference count the pause/resume of timers 42 private int mPauseTimerRefCount; 43 44 private boolean mTimerPaused; 45 private boolean mHasDeferredTimers; 46 47 // keep track of the main WebView attached to the current window so that we 48 // can get the proper Context. 49 private static WeakReference<WebView> sCurrentMainWebView = 50 new WeakReference<WebView>(null); 51 52 /* package */ 53 static final int REFRESH_PLUGINS = 100; 54 55 /** 56 * Construct a new JWebCoreJavaBridge to interface with 57 * WebCore timers and cookies. 58 */ 59 public JWebCoreJavaBridge() { 60 nativeConstructor(); 61 } 62 63 @Override 64 protected void finalize() { 65 nativeFinalize(); 66 } 67 68 static synchronized void setActiveWebView(WebView webview) { 69 if (sCurrentMainWebView.get() != null) { 70 // it is possible if there is a sub-WebView. Do nothing. 71 return; 72 } 73 sCurrentMainWebView = new WeakReference<WebView>(webview); 74 } 75 76 static synchronized void removeActiveWebView(WebView webview) { 77 if (sCurrentMainWebView.get() != webview) { 78 // it is possible if there is a sub-WebView. Do nothing. 79 return; 80 } 81 sCurrentMainWebView.clear(); 82 } 83 84 /** 85 * Call native timer callbacks. 86 */ 87 private void fireSharedTimer() { 88 PerfChecker checker = new PerfChecker(); 89 // clear the flag so that sharedTimerFired() can set a new timer 90 mHasInstantTimer = false; 91 sharedTimerFired(); 92 checker.responseAlert("sharedTimer"); 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 (--mPauseTimerRefCount == 0) { 136 mTimerPaused = true; 137 mHasDeferredTimers = false; 138 } 139 } 140 141 /** 142 * Resume all timers. 143 */ 144 public void resume() { 145 if (++mPauseTimerRefCount == 1) { 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 private native void nativeConstructor(); 275 private native void nativeFinalize(); 276 private native void sharedTimerFired(); 277 private native void nativeUpdatePluginDirectories(String[] directories, 278 boolean reload); 279 public native void setNetworkOnLine(boolean online); 280 public native void setNetworkType(String type, String subtype); 281 public native void addPackageNames(Set<String> packageNames); 282 public native void addPackageName(String packageName); 283 public native void removePackageName(String packageName); 284 } 285