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