| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.webkit; |
| |
| import android.net.ProxyProperties; |
| import android.net.Uri; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.util.Log; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.HashMap; |
| import java.util.Set; |
| |
| final class JWebCoreJavaBridge extends Handler { |
| // Identifier for the timer message. |
| private static final int TIMER_MESSAGE = 1; |
| // ID for servicing functionptr queue |
| private static final int FUNCPTR_MESSAGE = 2; |
| // Log system identifier. |
| private static final String LOGTAG = "webkit-timers"; |
| |
| // Native object pointer for interacting in native code. |
| private int mNativeBridge; |
| // Instant timer is used to implement a timer that needs to fire almost |
| // immediately. |
| private boolean mHasInstantTimer; |
| |
| private boolean mTimerPaused; |
| private boolean mHasDeferredTimers; |
| |
| // keep track of the main WebViewClassic attached to the current window so that we |
| // can get the proper Context. |
| private static WeakReference<WebViewClassic> sCurrentMainWebView = |
| new WeakReference<WebViewClassic>(null); |
| |
| /* package */ |
| static final int REFRESH_PLUGINS = 100; |
| |
| private HashMap<String, String> mContentUriToFilePathMap; |
| |
| /** |
| * Construct a new JWebCoreJavaBridge to interface with |
| * WebCore timers and cookies. |
| */ |
| public JWebCoreJavaBridge() { |
| nativeConstructor(); |
| |
| } |
| |
| @Override |
| protected void finalize() { |
| nativeFinalize(); |
| } |
| |
| static synchronized void setActiveWebView(WebViewClassic webview) { |
| if (sCurrentMainWebView.get() != null) { |
| // it is possible if there is a sub-WebView. Do nothing. |
| return; |
| } |
| sCurrentMainWebView = new WeakReference<WebViewClassic>(webview); |
| } |
| |
| static synchronized void removeActiveWebView(WebViewClassic webview) { |
| if (sCurrentMainWebView.get() != webview) { |
| // it is possible if there is a sub-WebView. Do nothing. |
| return; |
| } |
| sCurrentMainWebView.clear(); |
| } |
| |
| /** |
| * Call native timer callbacks. |
| */ |
| private void fireSharedTimer() { |
| // clear the flag so that sharedTimerFired() can set a new timer |
| mHasInstantTimer = false; |
| sharedTimerFired(); |
| } |
| |
| /** |
| * handleMessage |
| * @param msg The dispatched message. |
| * |
| * The only accepted message currently is TIMER_MESSAGE |
| */ |
| @Override |
| public void handleMessage(Message msg) { |
| switch (msg.what) { |
| case TIMER_MESSAGE: { |
| if (mTimerPaused) { |
| mHasDeferredTimers = true; |
| } else { |
| fireSharedTimer(); |
| } |
| break; |
| } |
| case FUNCPTR_MESSAGE: |
| nativeServiceFuncPtrQueue(); |
| break; |
| case REFRESH_PLUGINS: |
| nativeUpdatePluginDirectories(PluginManager.getInstance(null) |
| .getPluginDirectories(), ((Boolean) msg.obj) |
| .booleanValue()); |
| break; |
| } |
| } |
| |
| // called from JNI side |
| private void signalServiceFuncPtrQueue() { |
| Message msg = obtainMessage(FUNCPTR_MESSAGE); |
| sendMessage(msg); |
| } |
| |
| private native void nativeServiceFuncPtrQueue(); |
| |
| /** |
| * Pause all timers. |
| */ |
| public void pause() { |
| if (!mTimerPaused) { |
| mTimerPaused = true; |
| mHasDeferredTimers = false; |
| } |
| } |
| |
| /** |
| * Resume all timers. |
| */ |
| public void resume() { |
| if (mTimerPaused) { |
| mTimerPaused = false; |
| if (mHasDeferredTimers) { |
| mHasDeferredTimers = false; |
| fireSharedTimer(); |
| } |
| } |
| } |
| |
| /** |
| * Set WebCore cache size. |
| * @param bytes The cache size in bytes. |
| */ |
| public native void setCacheSize(int bytes); |
| |
| /** |
| * Store a cookie string associated with a url. |
| * @param url The url to be used as a key for the cookie. |
| * @param value The cookie string to be stored. |
| */ |
| private void setCookies(String url, String value) { |
| if (value.contains("\r") || value.contains("\n")) { |
| // for security reason, filter out '\r' and '\n' from the cookie |
| int size = value.length(); |
| StringBuilder buffer = new StringBuilder(size); |
| int i = 0; |
| while (i != -1 && i < size) { |
| int ir = value.indexOf('\r', i); |
| int in = value.indexOf('\n', i); |
| int newi = (ir == -1) ? in : (in == -1 ? ir : (ir < in ? ir |
| : in)); |
| if (newi > i) { |
| buffer.append(value.subSequence(i, newi)); |
| } else if (newi == -1) { |
| buffer.append(value.subSequence(i, size)); |
| break; |
| } |
| i = newi + 1; |
| } |
| value = buffer.toString(); |
| } |
| CookieManager.getInstance().setCookie(url, value); |
| } |
| |
| /** |
| * Retrieve the cookie string for the given url. |
| * @param url The resource's url. |
| * @return A String representing the cookies for the given resource url. |
| */ |
| private String cookies(String url) { |
| return CookieManager.getInstance().getCookie(url); |
| } |
| |
| /** |
| * Returns whether cookies are enabled or not. |
| */ |
| private boolean cookiesEnabled() { |
| return CookieManager.getInstance().acceptCookie(); |
| } |
| |
| /** |
| * Returns an array of plugin directoies |
| */ |
| private String[] getPluginDirectories() { |
| return PluginManager.getInstance(null).getPluginDirectories(); |
| } |
| |
| /** |
| * Returns the path of the plugin data directory |
| */ |
| private String getPluginSharedDataDirectory() { |
| return PluginManager.getInstance(null).getPluginSharedDataDirectory(); |
| } |
| |
| /** |
| * setSharedTimer |
| * @param timemillis The relative time when the timer should fire |
| */ |
| private void setSharedTimer(long timemillis) { |
| if (DebugFlags.J_WEB_CORE_JAVA_BRIDGE) Log.v(LOGTAG, "setSharedTimer " + timemillis); |
| |
| if (timemillis <= 0) { |
| // we don't accumulate the sharedTimer unless it is a delayed |
| // request. This way we won't flood the message queue with |
| // WebKit messages. This should improve the browser's |
| // responsiveness to key events. |
| if (mHasInstantTimer) { |
| return; |
| } else { |
| mHasInstantTimer = true; |
| Message msg = obtainMessage(TIMER_MESSAGE); |
| sendMessageDelayed(msg, timemillis); |
| } |
| } else { |
| Message msg = obtainMessage(TIMER_MESSAGE); |
| sendMessageDelayed(msg, timemillis); |
| } |
| } |
| |
| /** |
| * Stop the shared timer. |
| */ |
| private void stopSharedTimer() { |
| if (DebugFlags.J_WEB_CORE_JAVA_BRIDGE) { |
| Log.v(LOGTAG, "stopSharedTimer removing all timers"); |
| } |
| removeMessages(TIMER_MESSAGE); |
| mHasInstantTimer = false; |
| mHasDeferredTimers = false; |
| } |
| |
| private String[] getKeyStrengthList() { |
| return CertTool.getKeyStrengthList(); |
| } |
| |
| synchronized private String getSignedPublicKey(int index, String challenge, |
| String url) { |
| WebViewClassic current = sCurrentMainWebView.get(); |
| if (current != null) { |
| // generateKeyPair expects organizations which we don't have. Ignore |
| // url. |
| return CertTool.getSignedPublicKey( |
| current.getContext(), index, challenge); |
| } else { |
| Log.e(LOGTAG, "There is no active WebView for getSignedPublicKey"); |
| return ""; |
| } |
| } |
| |
| // Called on the WebCore thread through JNI. |
| private String resolveFilePathForContentUri(String uri) { |
| if (mContentUriToFilePathMap != null) { |
| String fileName = mContentUriToFilePathMap.get(uri); |
| if (fileName != null) { |
| return fileName; |
| } |
| } |
| |
| // Failsafe fallback to just use the last path segment. |
| // (See OpenableColumns documentation in the SDK) |
| Uri jUri = Uri.parse(uri); |
| return jUri.getLastPathSegment(); |
| } |
| |
| public void storeFilePathForContentUri(String path, String contentUri) { |
| if (mContentUriToFilePathMap == null) { |
| mContentUriToFilePathMap = new HashMap<String, String>(); |
| } |
| mContentUriToFilePathMap.put(contentUri, path); |
| } |
| |
| public void updateProxy(ProxyProperties proxyProperties) { |
| if (proxyProperties == null) { |
| nativeUpdateProxy("", ""); |
| return; |
| } |
| |
| String host = proxyProperties.getHost(); |
| int port = proxyProperties.getPort(); |
| if (port != 0) |
| host += ":" + port; |
| |
| nativeUpdateProxy(host, proxyProperties.getExclusionList()); |
| } |
| |
| private native void nativeConstructor(); |
| private native void nativeFinalize(); |
| private native void sharedTimerFired(); |
| private native void nativeUpdatePluginDirectories(String[] directories, |
| boolean reload); |
| public native void setNetworkOnLine(boolean online); |
| public native void setNetworkType(String type, String subtype); |
| public native void addPackageNames(Set<String> packageNames); |
| public native void addPackageName(String packageName); |
| public native void removePackageName(String packageName); |
| public native void nativeUpdateProxy(String newProxy, String exclusionList); |
| } |