summaryrefslogtreecommitdiffstats
path: root/core/java/android/webkit
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
commitd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/android/webkit
parent076357b8567458d4b6dfdcf839ef751634cd2bfb (diff)
downloadframeworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip
frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz
frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/webkit')
-rw-r--r--core/java/android/webkit/BrowserFrame.java786
-rw-r--r--core/java/android/webkit/ByteArrayBuilder.java142
-rw-r--r--core/java/android/webkit/CacheLoader.java65
-rw-r--r--core/java/android/webkit/CacheManager.java703
-rw-r--r--core/java/android/webkit/CallbackProxy.java1018
-rw-r--r--core/java/android/webkit/ContentLoader.java123
-rw-r--r--core/java/android/webkit/CookieManager.java934
-rw-r--r--core/java/android/webkit/CookieSyncManager.java205
-rw-r--r--core/java/android/webkit/DataLoader.java80
-rw-r--r--core/java/android/webkit/DateSorter.java124
-rw-r--r--core/java/android/webkit/DownloadListener.java33
-rw-r--r--core/java/android/webkit/FileLoader.java136
-rw-r--r--core/java/android/webkit/FrameLoader.java370
-rw-r--r--core/java/android/webkit/HttpAuthHandler.java186
-rw-r--r--core/java/android/webkit/HttpDateTime.java195
-rw-r--r--core/java/android/webkit/JWebCoreJavaBridge.java195
-rw-r--r--core/java/android/webkit/JsPromptResult.java52
-rw-r--r--core/java/android/webkit/JsResult.java82
-rw-r--r--core/java/android/webkit/LoadListener.java1499
-rw-r--r--core/java/android/webkit/MimeTypeMap.java503
-rw-r--r--core/java/android/webkit/Network.java349
-rw-r--r--core/java/android/webkit/PerfChecker.java49
-rw-r--r--core/java/android/webkit/Plugin.java126
-rw-r--r--core/java/android/webkit/PluginList.java83
-rw-r--r--core/java/android/webkit/SslErrorHandler.java255
-rw-r--r--core/java/android/webkit/StreamLoader.java199
-rw-r--r--core/java/android/webkit/TextDialog.java653
-rw-r--r--core/java/android/webkit/URLUtil.java363
-rw-r--r--core/java/android/webkit/UrlInterceptHandler.java34
-rw-r--r--core/java/android/webkit/UrlInterceptRegistry.java106
-rw-r--r--core/java/android/webkit/WebBackForwardList.java188
-rw-r--r--core/java/android/webkit/WebChromeClient.java160
-rw-r--r--core/java/android/webkit/WebHistoryItem.java179
-rw-r--r--core/java/android/webkit/WebIconDatabase.java251
-rw-r--r--core/java/android/webkit/WebSettings.java1112
-rw-r--r--core/java/android/webkit/WebSyncManager.java162
-rw-r--r--core/java/android/webkit/WebView.java5338
-rw-r--r--core/java/android/webkit/WebViewClient.java206
-rw-r--r--core/java/android/webkit/WebViewCore.java1672
-rw-r--r--core/java/android/webkit/WebViewDatabase.java967
-rw-r--r--core/java/android/webkit/gears/AndroidGpsLocationProvider.java156
-rw-r--r--core/java/android/webkit/gears/AndroidRadioDataProvider.java244
-rw-r--r--core/java/android/webkit/gears/AndroidWifiDataProvider.java136
-rw-r--r--core/java/android/webkit/gears/ApacheHttpRequestAndroid.java1122
-rw-r--r--core/java/android/webkit/gears/DesktopAndroid.java109
-rw-r--r--core/java/android/webkit/gears/NativeDialog.java142
-rw-r--r--core/java/android/webkit/gears/PluginSettings.java79
-rw-r--r--core/java/android/webkit/gears/UrlInterceptHandlerGears.java501
-rw-r--r--core/java/android/webkit/gears/VersionExtractor.java147
-rw-r--r--core/java/android/webkit/gears/ZipInflater.java200
-rw-r--r--core/java/android/webkit/gears/package.html3
-rw-r--r--core/java/android/webkit/package.html7
52 files changed, 0 insertions, 22729 deletions
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
deleted file mode 100644
index 451af6d..0000000
--- a/core/java/android/webkit/BrowserFrame.java
+++ /dev/null
@@ -1,786 +0,0 @@
-/*
- * 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.content.Context;
-import android.content.res.AssetManager;
-import android.graphics.Bitmap;
-import android.net.ParseException;
-import android.net.WebAddress;
-import android.net.http.SslCertificate;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Config;
-import android.util.Log;
-import android.util.TypedValue;
-
-import junit.framework.Assert;
-
-import java.net.URLEncoder;
-import java.util.HashMap;
-import java.util.Iterator;
-
-class BrowserFrame extends Handler {
-
- private static final String LOGTAG = "webkit";
-
- /**
- * Cap the number of LoadListeners that will be instantiated, so
- * we don't blow the GREF count. Attempting to queue more than
- * this many requests will prompt an error() callback on the
- * request's LoadListener
- */
- private final static int MAX_OUTSTANDING_REQUESTS = 300;
-
- private final CallbackProxy mCallbackProxy;
- private final WebSettings mSettings;
- private final Context mContext;
- private final WebViewDatabase mDatabase;
- private final WebViewCore mWebViewCore;
- /* package */ boolean mLoadInitFromJava;
- private int mLoadType;
- private boolean mFirstLayoutDone = true;
- private boolean mCommitted = true;
-
- // Is this frame the main frame?
- private boolean mIsMainFrame;
-
- // Attached Javascript interfaces
- private HashMap mJSInterfaceMap;
-
- // message ids
- // a message posted when a frame loading is completed
- static final int FRAME_COMPLETED = 1001;
- // a message posted when the user decides the policy
- static final int POLICY_FUNCTION = 1003;
-
- // Note: need to keep these in sync with FrameLoaderTypes.h in native
- static final int FRAME_LOADTYPE_STANDARD = 0;
- static final int FRAME_LOADTYPE_BACK = 1;
- static final int FRAME_LOADTYPE_FORWARD = 2;
- static final int FRAME_LOADTYPE_INDEXEDBACKFORWARD = 3;
- static final int FRAME_LOADTYPE_RELOAD = 4;
- static final int FRAME_LOADTYPE_RELOADALLOWINGSTALEDATA = 5;
- static final int FRAME_LOADTYPE_SAME = 6;
- static final int FRAME_LOADTYPE_REDIRECT = 7;
- static final int FRAME_LOADTYPE_REPLACE = 8;
-
- // A progress threshold to switch from history Picture to live Picture
- private static final int TRANSITION_SWITCH_THRESHOLD = 75;
-
- // This is a field accessed by native code as well as package classes.
- /*package*/ int mNativeFrame;
-
- // Static instance of a JWebCoreJavaBridge to handle timer and cookie
- // requests from WebCore.
- static JWebCoreJavaBridge sJavaBridge;
-
- /**
- * Create a new BrowserFrame to be used in an application.
- * @param context An application context to use when retrieving assets.
- * @param w A WebViewCore used as the view for this frame.
- * @param proxy A CallbackProxy for posting messages to the UI thread and
- * querying a client for information.
- * @param settings A WebSettings object that holds all settings.
- * XXX: Called by WebCore thread.
- */
- public BrowserFrame(Context context, WebViewCore w, CallbackProxy proxy,
- WebSettings settings) {
- // Create a global JWebCoreJavaBridge to handle timers and
- // cookies in the WebCore thread.
- if (sJavaBridge == null) {
- sJavaBridge = new JWebCoreJavaBridge();
- // set WebCore native cache size
- sJavaBridge.setCacheSize(4 * 1024 * 1024);
- // initialize CacheManager
- CacheManager.init(context);
- // create CookieSyncManager with current Context
- CookieSyncManager.createInstance(context);
- }
- AssetManager am = context.getAssets();
- nativeCreateFrame(w, am, proxy.getBackForwardList());
-
- mSettings = settings;
- mContext = context;
- mCallbackProxy = proxy;
- mDatabase = WebViewDatabase.getInstance(context);
- mWebViewCore = w;
-
- if (Config.LOGV) {
- Log.v(LOGTAG, "BrowserFrame constructor: this=" + this);
- }
- }
-
- /**
- * Load a url from the network or the filesystem into the main frame.
- * Following the same behaviour as Safari, javascript: URLs are not
- * passed to the main frame, instead they are evaluated immediately.
- * @param url The url to load.
- */
- public void loadUrl(String url) {
- mLoadInitFromJava = true;
- if (URLUtil.isJavaScriptUrl(url)) {
- // strip off the scheme and evaluate the string
- stringByEvaluatingJavaScriptFromString(
- url.substring("javascript:".length()));
- } else {
- nativeLoadUrl(url);
- }
- mLoadInitFromJava = false;
- }
-
- /**
- * Load the content as if it was loaded by the provided base URL. The
- * failUrl is used as the history entry for the load data. If null or
- * an empty string is passed for the failUrl, then no history entry is
- * created.
- *
- * @param baseUrl Base URL used to resolve relative paths in the content
- * @param data Content to render in the browser
- * @param mimeType Mimetype of the data being passed in
- * @param encoding Character set encoding of the provided data.
- * @param failUrl URL to use if the content fails to load or null.
- */
- public void loadData(String baseUrl, String data, String mimeType,
- String encoding, String failUrl) {
- mLoadInitFromJava = true;
- if (failUrl == null) {
- failUrl = "";
- }
- if (data == null) {
- data = "";
- }
-
- // Setup defaults for missing values. These defaults where taken from
- // WebKit's WebFrame.mm
- if (baseUrl == null || baseUrl.length() == 0) {
- baseUrl = "about:blank";
- }
- if (mimeType == null || mimeType.length() == 0) {
- mimeType = "text/html";
- }
- nativeLoadData(baseUrl, data, mimeType, encoding, failUrl);
- mLoadInitFromJava = false;
- }
-
- /**
- * Go back or forward the number of steps given.
- * @param steps A negative or positive number indicating the direction
- * and number of steps to move.
- */
- public void goBackOrForward(int steps) {
- mLoadInitFromJava = true;
- nativeGoBackOrForward(steps);
- mLoadInitFromJava = false;
- }
-
- /**
- * native callback
- * Report an error to an activity.
- * @param errorCode The HTTP error code.
- * @param description A String description.
- * TODO: Report all errors including resource errors but include some kind
- * of domain identifier. Change errorCode to an enum for a cleaner
- * interface.
- */
- private void reportError(final int errorCode, final String description,
- final String failingUrl) {
- // As this is called for the main resource and loading will be stopped
- // after, reset the state variables.
- mCommitted = true;
- mWebViewCore.mEndScaleZoom = mFirstLayoutDone == false;
- mFirstLayoutDone = true;
- mCallbackProxy.onReceivedError(errorCode, description, failingUrl);
- }
-
- /* package */boolean committed() {
- return mCommitted;
- }
-
- /* package */boolean firstLayoutDone() {
- return mFirstLayoutDone;
- }
-
- /* package */int loadType() {
- return mLoadType;
- }
-
- /* package */void didFirstLayout() {
- if (!mFirstLayoutDone) {
- mFirstLayoutDone = true;
- // ensure {@link WebViewCore#webkitDraw} is called as we were
- // blocking the update in {@link #loadStarted}
- mWebViewCore.contentDraw();
- }
- mWebViewCore.mEndScaleZoom = true;
- }
-
- /**
- * native callback
- * Indicates the beginning of a new load.
- * This method will be called once for the main frame.
- */
- private void loadStarted(String url, Bitmap favicon, int loadType,
- boolean isMainFrame) {
- mIsMainFrame = isMainFrame;
-
- if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
- mLoadType = loadType;
-
- if (isMainFrame) {
- // Call onPageStarted for main frames.
- mCallbackProxy.onPageStarted(url, favicon);
- // as didFirstLayout() is only called for the main frame, reset
- // mFirstLayoutDone only for the main frames
- mFirstLayoutDone = false;
- mCommitted = false;
- // remove pending draw to block update until mFirstLayoutDone is
- // set to true in didFirstLayout()
- mWebViewCore.removeMessages(WebViewCore.EventHub.WEBKIT_DRAW);
- }
-
- // Note: only saves committed form data in standard load
- if (loadType == FRAME_LOADTYPE_STANDARD
- && mSettings.getSaveFormData()) {
- final WebHistoryItem h = mCallbackProxy.getBackForwardList()
- .getCurrentItem();
- if (h != null) {
- String currentUrl = h.getUrl();
- if (currentUrl != null) {
- mDatabase.setFormData(currentUrl, getFormTextData());
- }
- }
- }
- }
- }
-
- /**
- * native callback
- * Indicates the WebKit has committed to the new load
- */
- private void transitionToCommitted(int loadType, boolean isMainFrame) {
- // loadType is not used yet
- if (isMainFrame) {
- mCommitted = true;
- }
- }
-
- /**
- * native callback
- * <p>
- * Indicates the end of a new load.
- * This method will be called once for the main frame.
- */
- private void loadFinished(String url, int loadType, boolean isMainFrame) {
- // mIsMainFrame and isMainFrame are better be equal!!!
-
- if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
- if (isMainFrame) {
- mCallbackProxy.switchOutDrawHistory();
- mCallbackProxy.onPageFinished(url);
- }
- }
- }
-
- /**
- * We have received an SSL certificate for the main top-level page.
- *
- * !!!Called from the network thread!!!
- */
- void certificate(SslCertificate certificate) {
- if (mIsMainFrame) {
- // we want to make this call even if the certificate is null
- // (ie, the site is not secure)
- mCallbackProxy.onReceivedCertificate(certificate);
- }
- }
-
- /**
- * Destroy all native components of the BrowserFrame.
- */
- public void destroy() {
- nativeDestroyFrame();
- removeCallbacksAndMessages(null);
- }
-
- /**
- * Handle messages posted to us.
- * @param msg The message to handle.
- */
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case FRAME_COMPLETED: {
- if (mSettings.getSavePassword() && hasPasswordField()) {
- if (Config.DEBUG) {
- Assert.assertNotNull(mCallbackProxy.getBackForwardList()
- .getCurrentItem());
- }
- WebAddress uri = new WebAddress(
- mCallbackProxy.getBackForwardList().getCurrentItem()
- .getUrl());
- String schemePlusHost = uri.mScheme + uri.mHost;
- String[] up = mDatabase.getUsernamePassword(schemePlusHost);
- if (up != null && up[0] != null) {
- setUsernamePassword(up[0], up[1]);
- }
- }
- CacheManager.trimCacheIfNeeded();
- break;
- }
-
- case POLICY_FUNCTION: {
- nativeCallPolicyFunction(msg.arg1, msg.arg2);
- break;
- }
-
- default:
- break;
- }
- }
-
- /**
- * Punch-through for WebCore to set the document
- * title. Inform the Activity of the new title.
- * @param title The new title of the document.
- */
- private void setTitle(String title) {
- // FIXME: The activity must call getTitle (a native method) to get the
- // title. We should try and cache the title if we can also keep it in
- // sync with the document.
- mCallbackProxy.onReceivedTitle(title);
- }
-
- /**
- * Retrieves the render tree of this frame and puts it as the object for
- * the message and sends the message.
- * @param callback the message to use to send the render tree
- */
- public void externalRepresentation(Message callback) {
- callback.obj = externalRepresentation();;
- callback.sendToTarget();
- }
-
- /**
- * Return the render tree as a string
- */
- private native String externalRepresentation();
-
- /**
- * Retrieves the visual text of the current frame, puts it as the object for
- * the message and sends the message.
- * @param callback the message to use to send the visual text
- */
- public void documentAsText(Message callback) {
- callback.obj = documentAsText();;
- callback.sendToTarget();
- }
-
- /**
- * Return the text drawn on the screen as a string
- */
- private native String documentAsText();
-
- /*
- * This method is called by WebCore to inform the frame that
- * the Javascript window object has been cleared.
- * We should re-attach any attached js interfaces.
- */
- private void windowObjectCleared(int nativeFramePointer) {
- if (mJSInterfaceMap != null) {
- Iterator iter = mJSInterfaceMap.keySet().iterator();
- while (iter.hasNext()) {
- String interfaceName = (String) iter.next();
- nativeAddJavascriptInterface(nativeFramePointer,
- mJSInterfaceMap.get(interfaceName), interfaceName);
- }
- }
- }
-
- /**
- * This method is called by WebCore to check whether application
- * wants to hijack url loading
- */
- public boolean handleUrl(String url) {
- if (mLoadInitFromJava == true) {
- return false;
- }
- if (mCallbackProxy.shouldOverrideUrlLoading(url)) {
- // if the url is hijacked, reset the state of the BrowserFrame
- didFirstLayout();
- return true;
- } else {
- return false;
- }
- }
-
- public void addJavascriptInterface(Object obj, String interfaceName) {
- if (mJSInterfaceMap == null) {
- mJSInterfaceMap = new HashMap<String, Object>();
- }
- if (mJSInterfaceMap.containsKey(interfaceName)) {
- mJSInterfaceMap.remove(interfaceName);
- }
- mJSInterfaceMap.put(interfaceName, obj);
- }
-
- /**
- * Start loading a resource.
- * @param loaderHandle The native ResourceLoader that is the target of the
- * data.
- * @param url The url to load.
- * @param method The http method.
- * @param headers The http headers.
- * @param postData If the method is "POST" postData is sent as the request
- * body. Is null when empty.
- * @param cacheMode The cache mode to use when loading this resource.
- * @param isHighPriority True if this resource needs to be put at the front
- * of the network queue.
- * @param synchronous True if the load is synchronous.
- * @return A newly created LoadListener object.
- */
- private LoadListener startLoadingResource(int loaderHandle,
- String url,
- String method,
- HashMap headers,
- byte[] postData,
- int cacheMode,
- boolean isHighPriority,
- boolean synchronous) {
- PerfChecker checker = new PerfChecker();
-
- if (mSettings.getCacheMode() != WebSettings.LOAD_DEFAULT) {
- cacheMode = mSettings.getCacheMode();
- }
-
- if (method.equals("POST")) {
- // Don't use the cache on POSTs when issuing a normal POST
- // request.
- if (cacheMode == WebSettings.LOAD_NORMAL) {
- cacheMode = WebSettings.LOAD_NO_CACHE;
- }
- if (mSettings.getSavePassword() && hasPasswordField()) {
- try {
- if (Config.DEBUG) {
- Assert.assertNotNull(mCallbackProxy.getBackForwardList()
- .getCurrentItem());
- }
- WebAddress uri = new WebAddress(mCallbackProxy
- .getBackForwardList().getCurrentItem().getUrl());
- String schemePlusHost = uri.mScheme + uri.mHost;
- String[] ret = getUsernamePassword();
- // Has the user entered a username/password pair and is
- // there some POST data
- if (ret != null && postData != null &&
- ret[0].length() > 0 && ret[1].length() > 0) {
- // Check to see if the username & password appear in
- // the post data (there could be another form on the
- // page and that was posted instead.
- String postString = new String(postData);
- if (postString.contains(URLEncoder.encode(ret[0])) &&
- postString.contains(URLEncoder.encode(ret[1]))) {
- String[] saved = mDatabase.getUsernamePassword(
- schemePlusHost);
- if (saved != null) {
- // null username implies that user has chosen not to
- // save password
- if (saved[0] != null) {
- // non-null username implies that user has
- // chosen to save password, so update the
- // recorded password
- mDatabase.setUsernamePassword(
- schemePlusHost, ret[0], ret[1]);
- }
- } else {
- // CallbackProxy will handle creating the resume
- // message
- mCallbackProxy.onSavePassword(schemePlusHost, ret[0],
- ret[1], null);
- }
- }
- }
- } catch (ParseException ex) {
- // if it is bad uri, don't save its password
- }
-
- }
- }
-
- // is this resource the main-frame top-level page?
- boolean isMainFramePage = mIsMainFrame;
-
- if (Config.LOGV) {
- Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method="
- + method + ", postData=" + postData + ", isHighPriority="
- + isHighPriority + ", isMainFramePage=" + isMainFramePage);
- }
-
- // Create a LoadListener
- LoadListener loadListener = LoadListener.getLoadListener(mContext, this, url,
- loaderHandle, synchronous, isMainFramePage);
-
- mCallbackProxy.onLoadResource(url);
-
- if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) {
- loadListener.error(
- android.net.http.EventHandler.ERROR, mContext.getString(
- com.android.internal.R.string.httpErrorTooManyRequests));
- loadListener.notifyError();
- loadListener.tearDown();
- return null;
- }
-
- // during synchronous load, the WebViewCore thread is blocked, so we
- // need to endCacheTransaction first so that http thread won't be
- // blocked in setupFile() when createCacheFile.
- if (synchronous) {
- CacheManager.endCacheTransaction();
- }
-
- FrameLoader loader = new FrameLoader(loadListener, mSettings,
- method, isHighPriority);
- loader.setHeaders(headers);
- loader.setPostData(postData);
- loader.setCacheMode(cacheMode); // Set the load mode to the mode used
- // for the current page.
- // Set referrer to current URL?
- if (!loader.executeLoad()) {
- checker.responseAlert("startLoadingResource fail");
- }
- checker.responseAlert("startLoadingResource succeed");
-
- if (synchronous) {
- CacheManager.startCacheTransaction();
- }
-
- return !synchronous ? loadListener : null;
- }
-
- /**
- * Set the progress for the browser activity. Called by native code.
- * Uses a delay so it does not happen too often.
- * @param newProgress An int between zero and one hundred representing
- * the current progress percentage of loading the page.
- */
- private void setProgress(int newProgress) {
- mCallbackProxy.onProgressChanged(newProgress);
- if (newProgress == 100) {
- sendMessageDelayed(obtainMessage(FRAME_COMPLETED), 100);
- }
- // FIXME: Need to figure out a better way to switch out of the history
- // drawing mode. Maybe we can somehow compare the history picture with
- // the current picture, and switch when it contains more content.
- if (mFirstLayoutDone && newProgress > TRANSITION_SWITCH_THRESHOLD) {
- mCallbackProxy.switchOutDrawHistory();
- }
- }
-
- /**
- * Send the icon to the activity for display.
- * @param icon A Bitmap representing a page's favicon.
- */
- private void didReceiveIcon(Bitmap icon) {
- mCallbackProxy.onReceivedIcon(icon);
- }
-
- /**
- * Request a new window from the client.
- * @return The BrowserFrame object stored in the new WebView.
- */
- private BrowserFrame createWindow(boolean dialog, boolean userGesture) {
- WebView w = mCallbackProxy.createWindow(dialog, userGesture);
- if (w != null) {
- return w.getWebViewCore().getBrowserFrame();
- }
- return null;
- }
-
- /**
- * Try to focus this WebView.
- */
- private void requestFocus() {
- mCallbackProxy.onRequestFocus();
- }
-
- /**
- * Close this frame and window.
- */
- private void closeWindow(WebViewCore w) {
- mCallbackProxy.onCloseWindow(w.getWebView());
- }
-
- // XXX: Must match PolicyAction in FrameLoaderTypes.h in webcore
- static final int POLICY_USE = 0;
- static final int POLICY_IGNORE = 2;
-
- private void decidePolicyForFormResubmission(int policyFunction) {
- Message dontResend = obtainMessage(POLICY_FUNCTION, policyFunction,
- POLICY_IGNORE);
- Message resend = obtainMessage(POLICY_FUNCTION, policyFunction,
- POLICY_USE);
- mCallbackProxy.onFormResubmission(dontResend, resend);
- }
-
- /**
- * Tell the activity to update its global history.
- */
- private void updateVisitedHistory(String url, boolean isReload) {
- mCallbackProxy.doUpdateVisitedHistory(url, isReload);
- }
-
- /**
- * Get the CallbackProxy for sending messages to the UI thread.
- */
- /* package */ CallbackProxy getCallbackProxy() {
- return mCallbackProxy;
- }
-
- /**
- * Returns the User Agent used by this frame
- */
- String getUserAgentString() {
- return mSettings.getUserAgentString();
- }
-
- // these ids need to be in sync with enum RAW_RES_ID in WebFrame
- private static final int NODOMAIN = 1;
- private static final int LOADERROR = 2;
-
- String getRawResFilename(int id) {
- int resid;
- switch (id) {
- case NODOMAIN:
- resid = com.android.internal.R.raw.nodomain;
- break;
-
- case LOADERROR:
- resid = com.android.internal.R.raw.loaderror;
- break;
-
- default:
- Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
- return new String();
- }
- TypedValue value = new TypedValue();
- mContext.getResources().getValue(resid, value, true);
- return value.string.toString();
- }
-
- //==========================================================================
- // native functions
- //==========================================================================
-
- /**
- * Create a new native frame for a given WebView
- * @param w A WebView that the frame draws into.
- * @param am AssetManager to use to get assets.
- * @param list The native side will add and remove items from this list as
- * the native list changes.
- */
- private native void nativeCreateFrame(WebViewCore w, AssetManager am,
- WebBackForwardList list);
-
- /**
- * Destroy the native frame.
- */
- public native void nativeDestroyFrame();
-
- private native void nativeCallPolicyFunction(int policyFunction,
- int decision);
-
- /**
- * Reload the current main frame.
- */
- public native void reload(boolean allowStale);
-
- /**
- * Go back or forward the number of steps given.
- * @param steps A negative or positive number indicating the direction
- * and number of steps to move.
- */
- private native void nativeGoBackOrForward(int steps);
-
- /**
- * stringByEvaluatingJavaScriptFromString will execute the
- * JS passed in in the context of this browser frame.
- * @param script A javascript string to execute
- *
- * @return string result of execution or null
- */
- public native String stringByEvaluatingJavaScriptFromString(String script);
-
- /**
- * Add a javascript interface to the main frame.
- */
- private native void nativeAddJavascriptInterface(int nativeFramePointer,
- Object obj, String interfaceName);
-
- /**
- * Enable or disable the native cache.
- */
- /* FIXME: The native cache is always on for now until we have a better
- * solution for our 2 caches. */
- private native void setCacheDisabled(boolean disabled);
-
- public native boolean cacheDisabled();
-
- public native void clearCache();
-
- /**
- * Returns false if the url is bad.
- */
- private native void nativeLoadUrl(String url);
-
- private native void nativeLoadData(String baseUrl, String data,
- String mimeType, String encoding, String failUrl);
-
- /**
- * Stop loading the current page.
- */
- public native void stopLoading();
-
- /**
- * Return true if the document has images.
- */
- public native boolean documentHasImages();
-
- /**
- * @return TRUE if there is a password field in the current frame
- */
- private native boolean hasPasswordField();
-
- /**
- * Get username and password in the current frame. If found, String[0] is
- * username and String[1] is password. Otherwise return NULL.
- * @return String[]
- */
- private native String[] getUsernamePassword();
-
- /**
- * Set username and password to the proper fields in the current frame
- * @param username
- * @param password
- */
- private native void setUsernamePassword(String username, String password);
-
- /**
- * Get form's "text" type data associated with the current frame.
- * @return HashMap If succeed, returns a list of name/value pair. Otherwise
- * returns null.
- */
- private native HashMap getFormTextData();
-}
diff --git a/core/java/android/webkit/ByteArrayBuilder.java b/core/java/android/webkit/ByteArrayBuilder.java
deleted file mode 100644
index 806b458..0000000
--- a/core/java/android/webkit/ByteArrayBuilder.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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 java.util.LinkedList;
-
-/** Utility class optimized for accumulating bytes, and then spitting
- them back out. It does not optimize for returning the result in a
- single array, though this is supported in the API. It is fastest
- if the retrieval can be done via iterating through chunks.
-
- Things to add:
- - consider dynamically increasing our min_capacity,
- as we see mTotalSize increase
-*/
-class ByteArrayBuilder {
-
- private static final int DEFAULT_CAPACITY = 8192;
-
- private LinkedList<Chunk> mChunks;
-
- /** free pool */
- private LinkedList<Chunk> mPool;
-
- private int mMinCapacity;
-
- public ByteArrayBuilder() {
- init(0);
- }
-
- public ByteArrayBuilder(int minCapacity) {
- init(minCapacity);
- }
-
- private void init(int minCapacity) {
- mChunks = new LinkedList<Chunk>();
- mPool = new LinkedList<Chunk>();
-
- if (minCapacity <= 0) {
- minCapacity = DEFAULT_CAPACITY;
- }
- mMinCapacity = minCapacity;
- }
-
- public void append(byte[] array) {
- append(array, 0, array.length);
- }
-
- public synchronized void append(byte[] array, int offset, int length) {
- while (length > 0) {
- Chunk c = appendChunk(length);
- int amount = Math.min(length, c.mArray.length - c.mLength);
- System.arraycopy(array, offset, c.mArray, c.mLength, amount);
- c.mLength += amount;
- length -= amount;
- offset += amount;
- }
- }
-
- /**
- * The fastest way to retrieve the data is to iterate through the
- * chunks. This returns the first chunk. Note: this pulls the
- * chunk out of the queue. The caller must call releaseChunk() to
- * dispose of it.
- */
- public synchronized Chunk getFirstChunk() {
- if (mChunks.isEmpty()) return null;
- return mChunks.removeFirst();
- }
-
- /**
- * recycles chunk
- */
- public synchronized void releaseChunk(Chunk c) {
- c.mLength = 0;
- mPool.addLast(c);
- }
-
- public boolean isEmpty() {
- return mChunks.isEmpty();
- }
-
- public synchronized void clear() {
- Chunk c = getFirstChunk();
- while (c != null) {
- releaseChunk(c);
- c = getFirstChunk();
- }
- }
-
- private Chunk appendChunk(int length) {
- if (length < mMinCapacity) {
- length = mMinCapacity;
- }
-
- Chunk c;
- if (mChunks.isEmpty()) {
- c = obtainChunk(length);
- } else {
- c = mChunks.getLast();
- if (c.mLength == c.mArray.length) {
- c = obtainChunk(length);
- }
- }
- return c;
- }
-
- private Chunk obtainChunk(int length) {
- Chunk c;
- if (mPool.isEmpty()) {
- c = new Chunk(length);
- } else {
- c = mPool.removeFirst();
- }
- mChunks.addLast(c);
- return c;
- }
-
- public static class Chunk {
- public byte[] mArray;
- public int mLength;
-
- public Chunk(int length) {
- mArray = new byte[length];
- mLength = 0;
- }
- }
-}
diff --git a/core/java/android/webkit/CacheLoader.java b/core/java/android/webkit/CacheLoader.java
deleted file mode 100644
index 3e1b602..0000000
--- a/core/java/android/webkit/CacheLoader.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2007 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.http.Headers;
-
-/**
- * This class is a concrete implementation of StreamLoader that uses a
- * CacheResult as the source for the stream. The CacheResult stored mimetype
- * and encoding is added to the HTTP response headers.
- */
-class CacheLoader extends StreamLoader {
-
- CacheManager.CacheResult mCacheResult; // Content source
-
- /**
- * Constructs a CacheLoader for use when loading content from the cache.
- *
- * @param loadListener LoadListener to pass the content to
- * @param result CacheResult used as the source for the content.
- */
- CacheLoader(LoadListener loadListener, CacheManager.CacheResult result) {
- super(loadListener);
- mCacheResult = result;
- }
-
- @Override
- protected boolean setupStreamAndSendStatus() {
- mDataStream = mCacheResult.inStream;
- mContentLength = mCacheResult.contentLength;
- mHandler.status(1, 1, mCacheResult.httpStatusCode, "OK");
- return true;
- }
-
- @Override
- protected void buildHeaders(Headers headers) {
- StringBuilder sb = new StringBuilder(mCacheResult.mimeType);
- if (mCacheResult.encoding != null &&
- mCacheResult.encoding.length() > 0) {
- sb.append(';');
- sb.append(mCacheResult.encoding);
- }
- headers.setContentType(sb.toString());
-
- if (mCacheResult.location != null &&
- mCacheResult.location.length() > 0) {
- headers.setLocation(mCacheResult.location);
- }
- }
-
-}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
deleted file mode 100644
index d12940d..0000000
--- a/core/java/android/webkit/CacheManager.java
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- * 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.content.Context;
-import android.net.http.Headers;
-import android.os.FileUtils;
-import android.util.Config;
-import android.util.Log;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Map;
-
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-
-/**
- * The class CacheManager provides the persistent cache of content that is
- * received over the network. The component handles parsing of HTTP headers and
- * utilizes the relevant cache headers to determine if the content should be
- * stored and if so, how long it is valid for. Network requests are provided to
- * this component and if they can not be resolved by the cache, the HTTP headers
- * are attached, as appropriate, to the request for revalidation of content. The
- * class also manages the cache size.
- */
-public final class CacheManager {
-
- private static final String LOGTAG = "cache";
-
- static final String HEADER_KEY_IFMODIFIEDSINCE = "if-modified-since";
- static final String HEADER_KEY_IFNONEMATCH = "if-none-match";
-
- private static final String NO_STORE = "no-store";
- private static final String NO_CACHE = "no-cache";
- private static final String MAX_AGE = "max-age";
-
- private static long CACHE_THRESHOLD = 6 * 1024 * 1024;
- private static long CACHE_TRIM_AMOUNT = 2 * 1024 * 1024;
-
- private static boolean mDisabled;
-
- // Reference count the enable/disable transaction
- private static int mRefCount;
-
- // trimCacheIfNeeded() is called when a page is fully loaded. But JavaScript
- // can load the content, e.g. in a slideshow, continuously, so we need to
- // trim the cache on a timer base too. endCacheTransaction() is called on a
- // timer base. We share the same timer with less frequent update.
- private static int mTrimCacheCount = 0;
- private static final int TRIM_CACHE_INTERVAL = 5;
-
- private static WebViewDatabase mDataBase;
- private static File mBaseDir;
-
- // Flag to clear the cache when the CacheManager is initialized
- private static boolean mClearCacheOnInit = false;
-
- public static class CacheResult {
- // these fields are saved to the database
- int httpStatusCode;
- long contentLength;
- long expires;
- String localPath;
- String lastModified;
- String etag;
- String mimeType;
- String location;
- String encoding;
-
- // these fields are NOT saved to the database
- InputStream inStream;
- OutputStream outStream;
- File outFile;
-
- public int getHttpStatusCode() {
- return httpStatusCode;
- }
-
- public long getContentLength() {
- return contentLength;
- }
-
- public String getLocalPath() {
- return localPath;
- }
-
- public long getExpires() {
- return expires;
- }
-
- public String getLastModified() {
- return lastModified;
- }
-
- public String getETag() {
- return etag;
- }
-
- public String getMimeType() {
- return mimeType;
- }
-
- public String getLocation() {
- return location;
- }
-
- public String getEncoding() {
- return encoding;
- }
-
- // For out-of-package access to the underlying streams.
- public InputStream getInputStream() {
- return inStream;
- }
-
- public OutputStream getOutputStream() {
- return outStream;
- }
-
- // These fields can be set manually.
- public void setInputStream(InputStream stream) {
- this.inStream = stream;
- }
-
- public void setEncoding(String encoding) {
- this.encoding = encoding;
- }
- }
-
- /**
- * initialize the CacheManager. WebView should handle this for each process.
- *
- * @param context The application context.
- */
- static void init(Context context) {
- mDataBase = WebViewDatabase.getInstance(context);
- mBaseDir = new File(context.getCacheDir(), "webviewCache");
- if (createCacheDirectory() && mClearCacheOnInit) {
- removeAllCacheFiles();
- mClearCacheOnInit = false;
- }
- }
-
- /**
- * Create the cache directory if it does not already exist.
- *
- * @return true if the cache directory didn't exist and was created.
- */
- static private boolean createCacheDirectory() {
- if (!mBaseDir.exists()) {
- if(!mBaseDir.mkdirs()) {
- Log.w(LOGTAG, "Unable to create webviewCache directory");
- return false;
- }
- FileUtils.setPermissions(
- mBaseDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
- -1, -1);
- // If we did create the directory, we need to flush
- // the cache database. The directory could be recreated
- // because the system flushed all the data/cache directories
- // to free up disk space.
- WebViewCore.endCacheTransaction();
- mDataBase.clearCache();
- WebViewCore.startCacheTransaction();
- return true;
- }
- return false;
- }
-
- /**
- * get the base directory of the cache. With localPath of the CacheResult,
- * it identifies the cache file.
- *
- * @return File The base directory of the cache.
- */
- public static File getCacheFileBaseDir() {
- return mBaseDir;
- }
-
- /**
- * set the flag to control whether cache is enabled or disabled
- *
- * @param disabled true to disable the cache
- */
- // only called from WebCore thread
- static void setCacheDisabled(boolean disabled) {
- if (disabled == mDisabled) {
- return;
- }
- mDisabled = disabled;
- if (mDisabled) {
- removeAllCacheFiles();
- }
- }
-
- /**
- * get the state of the current cache, enabled or disabled
- *
- * @return return if it is disabled
- */
- public static boolean cacheDisabled() {
- return mDisabled;
- }
-
- // only called from WebCore thread
- // make sure to call enableTransaction/disableTransaction in pair
- static boolean enableTransaction() {
- if (++mRefCount == 1) {
- mDataBase.startCacheTransaction();
- return true;
- }
- return false;
- }
-
- // only called from WebCore thread
- // make sure to call enableTransaction/disableTransaction in pair
- static boolean disableTransaction() {
- if (mRefCount == 0) {
- Log.e(LOGTAG, "disableTransaction is out of sync");
- }
- if (--mRefCount == 0) {
- mDataBase.endCacheTransaction();
- return true;
- }
- return false;
- }
-
- // only called from WebCore thread
- // make sure to call startCacheTransaction/endCacheTransaction in pair
- public static boolean startCacheTransaction() {
- return mDataBase.startCacheTransaction();
- }
-
- // only called from WebCore thread
- // make sure to call startCacheTransaction/endCacheTransaction in pair
- public static boolean endCacheTransaction() {
- boolean ret = mDataBase.endCacheTransaction();
- if (++mTrimCacheCount >= TRIM_CACHE_INTERVAL) {
- mTrimCacheCount = 0;
- trimCacheIfNeeded();
- }
- return ret;
- }
-
- /**
- * Given a url, returns the CacheResult if exists. Otherwise returns null.
- * If headers are provided and a cache needs validation,
- * HEADER_KEY_IFNONEMATCH or HEADER_KEY_IFMODIFIEDSINCE will be set in the
- * cached headers.
- *
- * @return the CacheResult for a given url
- */
- // only called from WebCore thread
- public static CacheResult getCacheFile(String url,
- Map<String, String> headers) {
- if (mDisabled) {
- return null;
- }
-
- CacheResult result = mDataBase.getCache(url);
- if (result != null) {
- if (result.contentLength == 0) {
- if (result.httpStatusCode != 301
- && result.httpStatusCode != 302
- && result.httpStatusCode != 307) {
- // this should not happen. If it does, remove it.
- mDataBase.removeCache(url);
- return null;
- }
- } else {
- File src = new File(mBaseDir, result.localPath);
- try {
- // open here so that even the file is deleted, the content
- // is still readable by the caller until close() is called
- result.inStream = new FileInputStream(src);
- } catch (FileNotFoundException e) {
- // the files in the cache directory can be removed by the
- // system. If it is gone, clean up the database
- mDataBase.removeCache(url);
- return null;
- }
- }
- } else {
- return null;
- }
-
- // null headers request coming from CACHE_MODE_CACHE_ONLY
- // which implies that it needs cache even it is expired.
- // negative expires means time in the far future.
- if (headers != null && result.expires >= 0
- && result.expires <= System.currentTimeMillis()) {
- if (result.lastModified == null && result.etag == null) {
- return null;
- }
- // return HEADER_KEY_IFNONEMATCH or HEADER_KEY_IFMODIFIEDSINCE
- // for requesting validation
- if (result.etag != null) {
- headers.put(HEADER_KEY_IFNONEMATCH, result.etag);
- }
- if (result.lastModified != null) {
- headers.put(HEADER_KEY_IFMODIFIEDSINCE, result.lastModified);
- }
- }
-
- if (Config.LOGV) {
- Log.v(LOGTAG, "getCacheFile for url " + url);
- }
-
- return result;
- }
-
- /**
- * Given a url and its full headers, returns CacheResult if a local cache
- * can be stored. Otherwise returns null. The mimetype is passed in so that
- * the function can use the mimetype that will be passed to WebCore which
- * could be different from the mimetype defined in the headers.
- * forceCache is for out-of-package callers to force creation of a
- * CacheResult, and is used to supply surrogate responses for URL
- * interception.
- * @return CacheResult for a given url
- * @hide - hide createCacheFile since it has a parameter of type headers, which is
- * in a hidden package.
- */
- // can be called from any thread
- public static CacheResult createCacheFile(String url, int statusCode,
- Headers headers, String mimeType, boolean forceCache) {
- if (!forceCache && mDisabled) {
- return null;
- }
-
- CacheResult ret = parseHeaders(statusCode, headers, mimeType);
- if (ret != null) {
- setupFiles(url, ret);
- try {
- ret.outStream = new FileOutputStream(ret.outFile);
- } catch (FileNotFoundException e) {
- // This can happen with the system did a purge and our
- // subdirectory has gone, so lets try to create it again
- if (createCacheDirectory()) {
- try {
- ret.outStream = new FileOutputStream(ret.outFile);
- } catch (FileNotFoundException e2) {
- // We failed to create the file again, so there
- // is something else wrong. Return null.
- return null;
- }
- } else {
- // Failed to create cache directory
- return null;
- }
- }
- ret.mimeType = mimeType;
- }
-
- return ret;
- }
-
- /**
- * Save the info of a cache file for a given url to the CacheMap so that it
- * can be reused later
- */
- // only called from WebCore thread
- public static void saveCacheFile(String url, CacheResult cacheRet) {
- try {
- cacheRet.outStream.close();
- } catch (IOException e) {
- return;
- }
-
- if (!cacheRet.outFile.exists()) {
- // the file in the cache directory can be removed by the system
- return;
- }
-
- cacheRet.contentLength = cacheRet.outFile.length();
- if (cacheRet.httpStatusCode == 301
- || cacheRet.httpStatusCode == 302
- || cacheRet.httpStatusCode == 307) {
- // location is in database, no need to keep the file
- cacheRet.contentLength = 0;
- cacheRet.localPath = new String();
- cacheRet.outFile.delete();
- } else if (cacheRet.contentLength == 0) {
- cacheRet.outFile.delete();
- return;
- }
-
- mDataBase.addCache(url, cacheRet);
-
- if (Config.LOGV) {
- Log.v(LOGTAG, "saveCacheFile for url " + url);
- }
- }
-
- /**
- * remove all cache files
- *
- * @return true if it succeeds
- */
- // only called from WebCore thread
- static boolean removeAllCacheFiles() {
- // Note, this is called before init() when the database is
- // created or upgraded.
- if (mBaseDir == null) {
- // Init() has not been called yet, so just flag that
- // we need to clear the cache when init() is called.
- mClearCacheOnInit = true;
- return true;
- }
- // delete cache in a separate thread to not block UI.
- final Runnable clearCache = new Runnable() {
- public void run() {
- // delete all cache files
- try {
- String[] files = mBaseDir.list();
- // if mBaseDir doesn't exist, files can be null.
- if (files != null) {
- for (int i = 0; i < files.length; i++) {
- new File(mBaseDir, files[i]).delete();
- }
- }
- } catch (SecurityException e) {
- // Ignore SecurityExceptions.
- }
- // delete database
- mDataBase.clearCache();
- }
- };
- new Thread(clearCache).start();
- return true;
- }
-
- /**
- * Return true if the cache is empty.
- */
- // only called from WebCore thread
- static boolean cacheEmpty() {
- return mDataBase.hasCache();
- }
-
- // only called from WebCore thread
- static void trimCacheIfNeeded() {
- if (mDataBase.getCacheTotalSize() > CACHE_THRESHOLD) {
- ArrayList<String> pathList = mDataBase.trimCache(CACHE_TRIM_AMOUNT);
- int size = pathList.size();
- for (int i = 0; i < size; i++) {
- new File(mBaseDir, pathList.get(i)).delete();
- }
- }
- }
-
- @SuppressWarnings("deprecation")
- private static void setupFiles(String url, CacheResult cacheRet) {
- if (true) {
- // Note: SHA1 is much stronger hash. But the cost of setupFiles() is
- // 3.2% cpu time for a fresh load of nytimes.com. While a simple
- // String.hashCode() is only 0.6%. If adding the collision resolving
- // to String.hashCode(), it makes the cpu time to be 1.6% for a
- // fresh load, but 5.3% for the worst case where all the files
- // already exist in the file system, but database is gone. So it
- // needs to resolve collision for every file at least once.
- int hashCode = url.hashCode();
- StringBuffer ret = new StringBuffer(8);
- appendAsHex(hashCode, ret);
- String path = ret.toString();
- File file = new File(mBaseDir, path);
- if (true) {
- boolean checkOldPath = true;
- // Check hash collision. If the hash file doesn't exist, just
- // continue. There is a chance that the old cache file is not
- // same as the hash file. As mDataBase.getCache() is more
- // expansive than "leak" a file until clear cache, don't bother.
- // If the hash file exists, make sure that it is same as the
- // cache file. If it is not, resolve the collision.
- while (file.exists()) {
- if (checkOldPath) {
- // as this is called from http thread through
- // createCacheFile, we need endCacheTransaction before
- // database access.
- WebViewCore.endCacheTransaction();
- CacheResult oldResult = mDataBase.getCache(url);
- WebViewCore.startCacheTransaction();
- if (oldResult != null && oldResult.contentLength > 0) {
- if (path.equals(oldResult.localPath)) {
- path = oldResult.localPath;
- } else {
- path = oldResult.localPath;
- file = new File(mBaseDir, path);
- }
- break;
- }
- checkOldPath = false;
- }
- ret = new StringBuffer(8);
- appendAsHex(++hashCode, ret);
- path = ret.toString();
- file = new File(mBaseDir, path);
- }
- }
- cacheRet.localPath = path;
- cacheRet.outFile = file;
- } else {
- // get hash in byte[]
- Digest digest = new SHA1Digest();
- int digestLen = digest.getDigestSize();
- byte[] hash = new byte[digestLen];
- int urlLen = url.length();
- byte[] data = new byte[urlLen];
- url.getBytes(0, urlLen, data, 0);
- digest.update(data, 0, urlLen);
- digest.doFinal(hash, 0);
- // convert byte[] to hex String
- StringBuffer result = new StringBuffer(2 * digestLen);
- for (int i = 0; i < digestLen; i = i + 4) {
- int h = (0x00ff & hash[i]) << 24 | (0x00ff & hash[i + 1]) << 16
- | (0x00ff & hash[i + 2]) << 8 | (0x00ff & hash[i + 3]);
- appendAsHex(h, result);
- }
- cacheRet.localPath = result.toString();
- cacheRet.outFile = new File(mBaseDir, cacheRet.localPath);
- }
- }
-
- private static void appendAsHex(int i, StringBuffer ret) {
- String hex = Integer.toHexString(i);
- switch (hex.length()) {
- case 1:
- ret.append("0000000");
- break;
- case 2:
- ret.append("000000");
- break;
- case 3:
- ret.append("00000");
- break;
- case 4:
- ret.append("0000");
- break;
- case 5:
- ret.append("000");
- break;
- case 6:
- ret.append("00");
- break;
- case 7:
- ret.append("0");
- break;
- }
- ret.append(hex);
- }
-
- private static CacheResult parseHeaders(int statusCode, Headers headers,
- String mimeType) {
- // TODO: if authenticated or secure, return null
- CacheResult ret = new CacheResult();
- ret.httpStatusCode = statusCode;
-
- String location = headers.getLocation();
- if (location != null) ret.location = location;
-
- ret.expires = -1;
- String expires = headers.getExpires();
- if (expires != null) {
- try {
- ret.expires = HttpDateTime.parse(expires);
- } catch (IllegalArgumentException ex) {
- // Take care of the special "-1" and "0" cases
- if ("-1".equals(expires) || "0".equals(expires)) {
- // make it expired, but can be used for history navigation
- ret.expires = 0;
- } else {
- Log.e(LOGTAG, "illegal expires: " + expires);
- }
- }
- }
-
- String lastModified = headers.getLastModified();
- if (lastModified != null) ret.lastModified = lastModified;
-
- String etag = headers.getEtag();
- if (etag != null) ret.etag = etag;
-
- String cacheControl = headers.getCacheControl();
- if (cacheControl != null) {
- String[] controls = cacheControl.toLowerCase().split("[ ,;]");
- for (int i = 0; i < controls.length; i++) {
- if (NO_STORE.equals(controls[i])) {
- return null;
- }
- // According to the spec, 'no-cache' means that the content
- // must be re-validated on every load. It does not mean that
- // the content can not be cached. set to expire 0 means it
- // can only be used in CACHE_MODE_CACHE_ONLY case
- if (NO_CACHE.equals(controls[i])) {
- ret.expires = 0;
- } else if (controls[i].startsWith(MAX_AGE)) {
- int separator = controls[i].indexOf('=');
- if (separator < 0) {
- separator = controls[i].indexOf(':');
- }
- if (separator > 0) {
- String s = controls[i].substring(separator + 1);
- try {
- long sec = Long.parseLong(s);
- if (sec >= 0) {
- ret.expires = System.currentTimeMillis() + 1000
- * sec;
- }
- } catch (NumberFormatException ex) {
- if ("1d".equals(s)) {
- // Take care of the special "1d" case
- ret.expires = System.currentTimeMillis() + 86400000; // 24*60*60*1000
- } else {
- Log.e(LOGTAG, "exception in parseHeaders for "
- + "max-age:"
- + controls[i].substring(separator + 1));
- ret.expires = 0;
- }
- }
- }
- }
- }
- }
-
- // According to RFC 2616 section 14.32:
- // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the
- // client had sent "Cache-Control: no-cache"
- if (NO_CACHE.equals(headers.getPragma())) {
- ret.expires = 0;
- }
-
- // According to RFC 2616 section 13.2.4, if an expiration has not been
- // explicitly defined a heuristic to set an expiration may be used.
- if (ret.expires == -1) {
- if (ret.httpStatusCode == 301) {
- // If it is a permanent redirect, and it did not have an
- // explicit cache directive, then it never expires
- ret.expires = Long.MAX_VALUE;
- } else if (ret.httpStatusCode == 302 || ret.httpStatusCode == 307) {
- // If it is temporary redirect, expires
- ret.expires = 0;
- } else if (ret.lastModified == null) {
- // When we have no last-modified, then expire the content with
- // in 24hrs as, according to the RFC, longer time requires a
- // warning 113 to be added to the response.
-
- // Only add the default expiration for non-html markup. Some
- // sites like news.google.com have no cache directives.
- if (!mimeType.startsWith("text/html")) {
- ret.expires = System.currentTimeMillis() + 86400000; // 24*60*60*1000
- } else {
- // Setting a expires as zero will cache the result for
- // forward/back nav.
- ret.expires = 0;
- }
- } else {
- // If we have a last-modified value, we could use it to set the
- // expiration. Suggestion from RFC is 10% of time since
- // last-modified. As we are on mobile, loads are expensive,
- // increasing this to 20%.
-
- // 24 * 60 * 60 * 1000
- long lastmod = System.currentTimeMillis() + 86400000;
- try {
- lastmod = HttpDateTime.parse(ret.lastModified);
- } catch (IllegalArgumentException ex) {
- Log.e(LOGTAG, "illegal lastModified: " + ret.lastModified);
- }
- long difference = System.currentTimeMillis() - lastmod;
- if (difference > 0) {
- ret.expires = System.currentTimeMillis() + difference / 5;
- } else {
- // last modified is in the future, expire the content
- // on the last modified
- ret.expires = lastmod;
- }
- }
- }
-
- return ret;
- }
-}
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
deleted file mode 100644
index 4f8e5e4..0000000
--- a/core/java/android/webkit/CallbackProxy.java
+++ /dev/null
@@ -1,1018 +0,0 @@
-/*
- * Copyright (C) 2007 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.app.AlertDialog;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.net.http.SslCertificate;
-import android.net.http.SslError;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.util.Config;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.TextView;
-import com.android.internal.R;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.HashMap;
-
-/**
- * This class is a proxy class for handling WebCore -> UI thread messaging. All
- * the callback functions are called from the WebCore thread and messages are
- * posted to the UI thread for the actual client callback.
- */
-/*
- * This class is created in the UI thread so its handler and any private classes
- * that extend Handler will operate in the UI thread.
- */
-class CallbackProxy extends Handler {
- // Logging tag
- private static final String LOGTAG = "CallbackProxy";
- // Instance of WebViewClient that is the client callback.
- private volatile WebViewClient mWebViewClient;
- // Instance of WebChromeClient for handling all chrome functions.
- private volatile WebChromeClient mWebChromeClient;
- // Instance of WebView for handling UI requests.
- private final WebView mWebView;
- // Client registered callback listener for download events
- private volatile DownloadListener mDownloadListener;
- // Keep track of multiple progress updates.
- private boolean mProgressUpdatePending;
- // Keep track of the last progress amount.
- private volatile int mLatestProgress;
- // Back/Forward list
- private final WebBackForwardList mBackForwardList;
- // Used to call startActivity during url override.
- private final Context mContext;
-
- // Message Ids
- private static final int PAGE_STARTED = 100;
- private static final int RECEIVED_ICON = 101;
- private static final int RECEIVED_TITLE = 102;
- private static final int OVERRIDE_URL = 103;
- private static final int AUTH_REQUEST = 104;
- private static final int SSL_ERROR = 105;
- private static final int PROGRESS = 106;
- private static final int UPDATE_VISITED = 107;
- private static final int LOAD_RESOURCE = 108;
- private static final int CREATE_WINDOW = 109;
- private static final int CLOSE_WINDOW = 110;
- private static final int SAVE_PASSWORD = 111;
- private static final int JS_ALERT = 112;
- private static final int JS_CONFIRM = 113;
- private static final int JS_PROMPT = 114;
- private static final int JS_UNLOAD = 115;
- private static final int ASYNC_KEYEVENTS = 116;
- private static final int TOO_MANY_REDIRECTS = 117;
- private static final int DOWNLOAD_FILE = 118;
- private static final int REPORT_ERROR = 119;
- private static final int RESEND_POST_DATA = 120;
- private static final int PAGE_FINISHED = 121;
- private static final int REQUEST_FOCUS = 122;
- private static final int SCALE_CHANGED = 123;
- private static final int RECEIVED_CERTIFICATE = 124;
- private static final int SWITCH_OUT_HISTORY = 125;
-
- // Message triggered by the client to resume execution
- private static final int NOTIFY = 200;
-
- // Result transportation object for returning results across thread
- // boundaries.
- private class ResultTransport<E> {
- // Private result object
- private E mResult;
-
- public synchronized void setResult(E result) {
- mResult = result;
- }
-
- public synchronized E getResult() {
- return mResult;
- }
- }
-
- /**
- * Construct a new CallbackProxy.
- */
- public CallbackProxy(Context context, WebView w) {
- // Used to start a default activity.
- mContext = context;
- mWebView = w;
- mBackForwardList = new WebBackForwardList();
- }
-
- /**
- * Set the WebViewClient.
- * @param client An implementation of WebViewClient.
- */
- public void setWebViewClient(WebViewClient client) {
- mWebViewClient = client;
- }
-
- /**
- * Set the WebChromeClient.
- * @param client An implementation of WebChromeClient.
- */
- public void setWebChromeClient(WebChromeClient client) {
- mWebChromeClient = client;
- }
-
- /**
- * Set the client DownloadListener.
- * @param client An implementation of DownloadListener.
- */
- public void setDownloadListener(DownloadListener client) {
- mDownloadListener = client;
- }
-
- /**
- * Get the Back/Forward list to return to the user or to update the cached
- * history list.
- */
- public WebBackForwardList getBackForwardList() {
- return mBackForwardList;
- }
-
- /**
- * Called by the UI side. Calling overrideUrlLoading from the WebCore
- * side will post a message to call this method.
- */
- public boolean uiOverrideUrlLoading(String overrideUrl) {
- if (overrideUrl == null || overrideUrl.length() == 0) {
- return false;
- }
- boolean override = false;
- if (mWebViewClient != null) {
- override = mWebViewClient.shouldOverrideUrlLoading(mWebView,
- overrideUrl);
- } else {
- Intent intent = new Intent(Intent.ACTION_VIEW,
- Uri.parse(overrideUrl));
- intent.addCategory(Intent.CATEGORY_BROWSABLE);
- try {
- mContext.startActivity(intent);
- override = true;
- } catch (ActivityNotFoundException ex) {
- // If no application can handle the URL, assume that the
- // browser can handle it.
- }
- }
- return override;
- }
-
- /**
- * Called by UI side.
- */
- public boolean uiOverrideKeyEvent(KeyEvent event) {
- if (mWebViewClient != null) {
- return mWebViewClient.shouldOverrideKeyEvent(mWebView, event);
- }
- return false;
- }
-
- @Override
- public void handleMessage(Message msg) {
- // We don't have to do synchronization because this function operates
- // in the UI thread. The WebViewClient and WebChromeClient functions
- // that check for a non-null callback are ok because java ensures atomic
- // 32-bit reads and writes.
- switch (msg.what) {
- case PAGE_STARTED:
- if (mWebViewClient != null) {
- mWebViewClient.onPageStarted(mWebView,
- msg.getData().getString("url"),
- (Bitmap) msg.obj);
- }
- break;
-
- case PAGE_FINISHED:
- if (mWebViewClient != null) {
- mWebViewClient.onPageFinished(mWebView, (String) msg.obj);
- }
- break;
-
- case RECEIVED_ICON:
- if (mWebChromeClient != null) {
- mWebChromeClient.onReceivedIcon(mWebView, (Bitmap) msg.obj);
- }
- break;
-
- case RECEIVED_TITLE:
- if (mWebChromeClient != null) {
- mWebChromeClient.onReceivedTitle(mWebView,
- (String) msg.obj);
- }
- break;
-
- case TOO_MANY_REDIRECTS:
- Message cancelMsg =
- (Message) msg.getData().getParcelable("cancelMsg");
- Message continueMsg =
- (Message) msg.getData().getParcelable("continueMsg");
- if (mWebViewClient != null) {
- mWebViewClient.onTooManyRedirects(mWebView, cancelMsg,
- continueMsg);
- } else {
- cancelMsg.sendToTarget();
- }
- break;
-
- case REPORT_ERROR:
- if (mWebViewClient != null) {
- int reasonCode = msg.arg1;
- final String description = msg.getData().getString("description");
- final String failUrl = msg.getData().getString("failingUrl");
- mWebViewClient.onReceivedError(mWebView, reasonCode,
- description, failUrl);
- }
- break;
-
- case RESEND_POST_DATA:
- Message resend =
- (Message) msg.getData().getParcelable("resend");
- Message dontResend =
- (Message) msg.getData().getParcelable("dontResend");
- if (mWebViewClient != null) {
- mWebViewClient.onFormResubmission(mWebView, dontResend,
- resend);
- } else {
- dontResend.sendToTarget();
- }
- break;
-
- case OVERRIDE_URL:
- String overrideUrl = msg.getData().getString("url");
- boolean override = uiOverrideUrlLoading(overrideUrl);
- ResultTransport<Boolean> result =
- (ResultTransport<Boolean>) msg.obj;
- synchronized (this) {
- result.setResult(override);
- notify();
- }
- break;
-
- case AUTH_REQUEST:
- if (mWebViewClient != null) {
- HttpAuthHandler handler = (HttpAuthHandler) msg.obj;
- String host = msg.getData().getString("host");
- String realm = msg.getData().getString("realm");
- mWebViewClient.onReceivedHttpAuthRequest(mWebView, handler,
- host, realm);
- }
- break;
-
- case SSL_ERROR:
- if (mWebViewClient != null) {
- HashMap<String, Object> map =
- (HashMap<String, Object>) msg.obj;
- mWebViewClient.onReceivedSslError(mWebView,
- (SslErrorHandler) map.get("handler"),
- (SslError) map.get("error"));
- }
- break;
-
- case PROGRESS:
- // Synchronize to ensure mLatestProgress is not modified after
- // setProgress is called and before mProgressUpdatePending is
- // changed.
- synchronized (this) {
- if (mWebChromeClient != null) {
- mWebChromeClient.onProgressChanged(mWebView,
- mLatestProgress);
- }
- mProgressUpdatePending = false;
- }
- break;
-
- case UPDATE_VISITED:
- if (mWebViewClient != null) {
- mWebViewClient.doUpdateVisitedHistory(mWebView,
- (String) msg.obj, msg.arg1 != 0);
- }
- break;
-
- case LOAD_RESOURCE:
- if (mWebViewClient != null) {
- mWebViewClient.onLoadResource(mWebView, (String) msg.obj);
- }
- break;
-
- case DOWNLOAD_FILE:
- if (mDownloadListener != null) {
- String url = msg.getData().getString("url");
- String userAgent = msg.getData().getString("userAgent");
- String contentDisposition =
- msg.getData().getString("contentDisposition");
- String mimetype = msg.getData().getString("mimetype");
- Long contentLength = msg.getData().getLong("contentLength");
-
- mDownloadListener.onDownloadStart(url, userAgent,
- contentDisposition, mimetype, contentLength);
- }
- break;
-
- case CREATE_WINDOW:
- if (mWebChromeClient != null) {
- if (!mWebChromeClient.onCreateWindow(mWebView,
- msg.arg1 == 1, msg.arg2 == 1,
- (Message) msg.obj)) {
- synchronized (this) {
- notify();
- }
- }
- }
- break;
-
- case REQUEST_FOCUS:
- if (mWebChromeClient != null) {
- mWebChromeClient.onRequestFocus(mWebView);
- }
- break;
-
- case CLOSE_WINDOW:
- if (mWebChromeClient != null) {
- mWebChromeClient.onCloseWindow((WebView) msg.obj);
- }
- break;
-
- case SAVE_PASSWORD:
- Bundle bundle = msg.getData();
- String schemePlusHost = bundle.getString("host");
- String username = bundle.getString("username");
- String password = bundle.getString("password");
- // If the client returned false it means that the notify message
- // will not be sent and we should notify WebCore ourselves.
- if (!mWebView.onSavePassword(schemePlusHost, username, password,
- (Message) msg.obj)) {
- synchronized (this) {
- notify();
- }
- }
- break;
-
- case ASYNC_KEYEVENTS:
- if (mWebViewClient != null) {
- mWebViewClient.onUnhandledKeyEvent(mWebView,
- (KeyEvent) msg.obj);
- }
- break;
-
- case JS_ALERT:
- if (mWebChromeClient != null) {
- final JsResult res = (JsResult) msg.obj;
- String message = msg.getData().getString("message");
- String url = msg.getData().getString("url");
- if (!mWebChromeClient.onJsAlert(mWebView, url, message,
- res)) {
- new AlertDialog.Builder(mContext)
- .setTitle(getJsDialogTitle(url))
- .setMessage(message)
- .setPositiveButton(R.string.ok,
- new AlertDialog.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.confirm();
- }
- })
- .setCancelable(false)
- .show();
- }
- res.setReady();
- }
- break;
-
- case JS_CONFIRM:
- if (mWebChromeClient != null) {
- final JsResult res = (JsResult) msg.obj;
- String message = msg.getData().getString("message");
- String url = msg.getData().getString("url");
- if (!mWebChromeClient.onJsConfirm(mWebView, url, message,
- res)) {
- new AlertDialog.Builder(mContext)
- .setTitle(getJsDialogTitle(url))
- .setMessage(message)
- .setPositiveButton(R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.confirm();
- }})
- .setNegativeButton(R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.cancel();
- }})
- .show();
- }
- // Tell the JsResult that it is ready for client
- // interaction.
- res.setReady();
- }
- break;
-
- case JS_PROMPT:
- if (mWebChromeClient != null) {
- final JsPromptResult res = (JsPromptResult) msg.obj;
- String message = msg.getData().getString("message");
- String defaultVal = msg.getData().getString("default");
- String url = msg.getData().getString("url");
- if (!mWebChromeClient.onJsPrompt(mWebView, url, message,
- defaultVal, res)) {
- final LayoutInflater factory = LayoutInflater
- .from(mContext);
- final View view = factory.inflate(R.layout.js_prompt,
- null);
- final EditText v = (EditText) view
- .findViewById(R.id.value);
- v.setText(defaultVal);
- ((TextView) view.findViewById(R.id.message))
- .setText(message);
- new AlertDialog.Builder(mContext)
- .setTitle(getJsDialogTitle(url))
- .setView(view)
- .setPositiveButton(R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int whichButton) {
- res.confirm(v.getText()
- .toString());
- }
- })
- .setNegativeButton(R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int whichButton) {
- res.cancel();
- }
- })
- .setOnCancelListener(
- new DialogInterface.OnCancelListener() {
- public void onCancel(
- DialogInterface dialog) {
- res.cancel();
- }
- })
- .show();
- }
- // Tell the JsResult that it is ready for client
- // interaction.
- res.setReady();
- }
- break;
-
- case JS_UNLOAD:
- if (mWebChromeClient != null) {
- final JsResult res = (JsResult) msg.obj;
- String message = msg.getData().getString("message");
- String url = msg.getData().getString("url");
- if (!mWebChromeClient.onJsBeforeUnload(mWebView, url,
- message, res)) {
- final String m = mContext.getString(
- R.string.js_dialog_before_unload, message);
- new AlertDialog.Builder(mContext)
- .setMessage(m)
- .setPositiveButton(R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.confirm();
- }
- })
- .setNegativeButton(R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.cancel();
- }
- })
- .show();
- }
- res.setReady();
- }
- break;
-
- case RECEIVED_CERTIFICATE:
- mWebView.setCertificate((SslCertificate) msg.obj);
- break;
-
- case NOTIFY:
- synchronized (this) {
- notify();
- }
- break;
-
- case SCALE_CHANGED:
- if (mWebViewClient != null) {
- mWebViewClient.onScaleChanged(mWebView, msg.getData()
- .getFloat("old"), msg.getData().getFloat("new"));
- }
- break;
-
- case SWITCH_OUT_HISTORY:
- mWebView.switchOutDrawHistory();
- break;
- }
- }
-
- /**
- * Return the latest progress.
- */
- public int getProgress() {
- return mLatestProgress;
- }
-
- /**
- * Called by WebCore side to switch out of history Picture drawing mode
- */
- void switchOutDrawHistory() {
- sendMessage(obtainMessage(SWITCH_OUT_HISTORY));
- }
-
- private String getJsDialogTitle(String url) {
- String title = url;
- if (URLUtil.isDataUrl(url)) {
- // For data: urls, we just display 'JavaScript' similar to Safari.
- title = mContext.getString(R.string.js_dialog_title_default);
- } else {
- try {
- URL aUrl = new URL(url);
- // For example: "The page at 'http://www.mit.edu' says:"
- title = mContext.getString(R.string.js_dialog_title,
- aUrl.getProtocol() + "://" + aUrl.getHost());
- } catch (MalformedURLException ex) {
- // do nothing. just use the url as the title
- }
- }
- return title;
- }
-
- //--------------------------------------------------------------------------
- // WebViewClient functions.
- // NOTE: shouldOverrideKeyEvent is never called from the WebCore thread so
- // it is not necessary to include it here.
- //--------------------------------------------------------------------------
-
- // Performance probe
- private long mWebCoreThreadTime;
-
- public void onPageStarted(String url, Bitmap favicon) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- return;
- }
- // Performance probe
- if (false) {
- mWebCoreThreadTime = SystemClock.currentThreadTimeMillis();
- Network.getInstance(mContext).startTiming();
- }
- Message msg = obtainMessage(PAGE_STARTED);
- msg.obj = favicon;
- msg.getData().putString("url", url);
- sendMessage(msg);
- }
-
- public void onPageFinished(String url) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- return;
- }
- // Performance probe
- if (false) {
- Log.d("WebCore", "WebCore thread used " +
- (SystemClock.currentThreadTimeMillis() - mWebCoreThreadTime)
- + " ms");
- Network.getInstance(mContext).stopTiming();
- }
- Message msg = obtainMessage(PAGE_FINISHED, url);
- sendMessage(msg);
- }
-
- public void onTooManyRedirects(Message cancelMsg, Message continueMsg) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- cancelMsg.sendToTarget();
- return;
- }
-
- Message msg = obtainMessage(TOO_MANY_REDIRECTS);
- Bundle bundle = msg.getData();
- bundle.putParcelable("cancelMsg", cancelMsg);
- bundle.putParcelable("continueMsg", continueMsg);
- sendMessage(msg);
- }
-
- public void onReceivedError(int errorCode, String description,
- String failingUrl) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- return;
- }
-
- Message msg = obtainMessage(REPORT_ERROR);
- msg.arg1 = errorCode;
- msg.getData().putString("description", description);
- msg.getData().putString("failingUrl", failingUrl);
- sendMessage(msg);
- }
-
- public void onFormResubmission(Message dontResend,
- Message resend) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- dontResend.sendToTarget();
- return;
- }
-
- Message msg = obtainMessage(RESEND_POST_DATA);
- Bundle bundle = msg.getData();
- bundle.putParcelable("resend", resend);
- bundle.putParcelable("dontResend", dontResend);
- sendMessage(msg);
- }
-
- /**
- * Called by the WebCore side
- */
- public boolean shouldOverrideUrlLoading(String url) {
- // We have a default behavior if no client exists so always send the
- // message.
- ResultTransport<Boolean> res = new ResultTransport<Boolean>();
- Message msg = obtainMessage(OVERRIDE_URL);
- msg.getData().putString("url", url);
- msg.obj = res;
- synchronized (this) {
- sendMessage(msg);
- try {
- wait();
- } catch (InterruptedException e) {
- Log.e(LOGTAG, "Caught exception while waiting for overrideUrl");
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
- }
- return res.getResult().booleanValue();
- }
-
- public void onReceivedHttpAuthRequest(HttpAuthHandler handler,
- String hostName, String realmName) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- handler.cancel();
- return;
- }
- Message msg = obtainMessage(AUTH_REQUEST, handler);
- msg.getData().putString("host", hostName);
- msg.getData().putString("realm", realmName);
- sendMessage(msg);
- }
- /**
- * @hide - hide this because it contains a parameter of type SslError.
- * SslError is located in a hidden package.
- */
- public void onReceivedSslError(SslErrorHandler handler, SslError error) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- handler.cancel();
- return;
- }
- Message msg = obtainMessage(SSL_ERROR);
- //, handler);
- HashMap<String, Object> map = new HashMap();
- map.put("handler", handler);
- map.put("error", error);
- msg.obj = map;
- sendMessage(msg);
- }
- /**
- * @hide - hide this because it contains a parameter of type SslCertificate,
- * which is located in a hidden package.
- */
-
- public void onReceivedCertificate(SslCertificate certificate) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- return;
- }
- // here, certificate can be null (if the site is not secure)
- sendMessage(obtainMessage(RECEIVED_CERTIFICATE, certificate));
- }
-
- public void doUpdateVisitedHistory(String url, boolean isReload) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- return;
- }
- sendMessage(obtainMessage(UPDATE_VISITED, isReload ? 1 : 0, 0, url));
- }
-
- public void onLoadResource(String url) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- return;
- }
- sendMessage(obtainMessage(LOAD_RESOURCE, url));
- }
-
- public void onUnhandledKeyEvent(KeyEvent event) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- return;
- }
- sendMessage(obtainMessage(ASYNC_KEYEVENTS, event));
- }
-
- public void onScaleChanged(float oldScale, float newScale) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebViewClient == null) {
- return;
- }
- Message msg = obtainMessage(SCALE_CHANGED);
- Bundle bundle = msg.getData();
- bundle.putFloat("old", oldScale);
- bundle.putFloat("new", newScale);
- sendMessage(msg);
- }
-
- //--------------------------------------------------------------------------
- // DownloadListener functions.
- //--------------------------------------------------------------------------
-
- /**
- * Starts a download if a download listener has been registered, otherwise
- * return false.
- */
- public boolean onDownloadStart(String url, String userAgent,
- String contentDisposition, String mimetype, long contentLength) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mDownloadListener == null) {
- // Cancel the download if there is no browser client.
- return false;
- }
-
- Message msg = obtainMessage(DOWNLOAD_FILE);
- Bundle bundle = msg.getData();
- bundle.putString("url", url);
- bundle.putString("userAgent", userAgent);
- bundle.putString("mimetype", mimetype);
- bundle.putLong("contentLength", contentLength);
- bundle.putString("contentDisposition", contentDisposition);
- sendMessage(msg);
- return true;
- }
-
-
- //--------------------------------------------------------------------------
- // WebView specific functions that do not interact with a client. These
- // functions just need to operate within the UI thread.
- //--------------------------------------------------------------------------
-
- public boolean onSavePassword(String schemePlusHost, String username,
- String password, Message resumeMsg) {
- // resumeMsg should be null at this point because we want to create it
- // within the CallbackProxy.
- if (Config.DEBUG) {
- junit.framework.Assert.assertNull(resumeMsg);
- }
- resumeMsg = obtainMessage(NOTIFY);
-
- Message msg = obtainMessage(SAVE_PASSWORD, resumeMsg);
- Bundle bundle = msg.getData();
- bundle.putString("host", schemePlusHost);
- bundle.putString("username", username);
- bundle.putString("password", password);
- synchronized (this) {
- sendMessage(msg);
- try {
- wait();
- } catch (InterruptedException e) {
- Log.e(LOGTAG,
- "Caught exception while waiting for onSavePassword");
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
- }
- // Doesn't matter here
- return false;
- }
-
- //--------------------------------------------------------------------------
- // WebChromeClient methods
- //--------------------------------------------------------------------------
-
- public void onProgressChanged(int newProgress) {
- // Synchronize so that mLatestProgress is up-to-date.
- synchronized (this) {
- mLatestProgress = newProgress;
- if (mWebChromeClient == null) {
- return;
- }
- if (!mProgressUpdatePending) {
- sendEmptyMessage(PROGRESS);
- mProgressUpdatePending = true;
- }
- }
- }
-
- public WebView createWindow(boolean dialog, boolean userGesture) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebChromeClient == null) {
- return null;
- }
-
- WebView.WebViewTransport transport = mWebView.new WebViewTransport();
- final Message msg = obtainMessage(NOTIFY);
- msg.obj = transport;
- synchronized (this) {
- sendMessage(obtainMessage(CREATE_WINDOW, dialog ? 1 : 0,
- userGesture ? 1 : 0, msg));
- try {
- wait();
- } catch (InterruptedException e) {
- Log.e(LOGTAG,
- "Caught exception while waiting for createWindow");
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
- }
-
- WebView w = transport.getWebView();
- if (w != null) {
- w.getWebViewCore().initializeSubwindow();
- }
- return w;
- }
-
- public void onRequestFocus() {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebChromeClient == null) {
- return;
- }
-
- sendEmptyMessage(REQUEST_FOCUS);
- }
-
- public void onCloseWindow(WebView window) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebChromeClient == null) {
- return;
- }
- sendMessage(obtainMessage(CLOSE_WINDOW, window));
- }
-
- public void onReceivedIcon(Bitmap icon) {
- if (Config.DEBUG && mBackForwardList.getCurrentItem() == null) {
- throw new AssertionError();
- }
- mBackForwardList.getCurrentItem().setFavicon(icon);
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebChromeClient == null) {
- return;
- }
- sendMessage(obtainMessage(RECEIVED_ICON, icon));
- }
-
- public void onReceivedTitle(String title) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebChromeClient == null) {
- return;
- }
- sendMessage(obtainMessage(RECEIVED_TITLE, title));
- }
-
- public void onJsAlert(String url, String message) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebChromeClient == null) {
- return;
- }
- JsResult result = new JsResult(this, false);
- Message alert = obtainMessage(JS_ALERT, result);
- alert.getData().putString("message", message);
- alert.getData().putString("url", url);
- synchronized (this) {
- sendMessage(alert);
- try {
- wait();
- } catch (InterruptedException e) {
- Log.e(LOGTAG, "Caught exception while waiting for jsAlert");
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
- }
- }
-
- public boolean onJsConfirm(String url, String message) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebChromeClient == null) {
- return false;
- }
- JsResult result = new JsResult(this, false);
- Message confirm = obtainMessage(JS_CONFIRM, result);
- confirm.getData().putString("message", message);
- confirm.getData().putString("url", url);
- synchronized (this) {
- sendMessage(confirm);
- try {
- wait();
- } catch (InterruptedException e) {
- Log.e(LOGTAG, "Caught exception while waiting for jsConfirm");
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
- }
- return result.getResult();
- }
-
- public String onJsPrompt(String url, String message, String defaultValue) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebChromeClient == null) {
- return null;
- }
- JsPromptResult result = new JsPromptResult(this);
- Message prompt = obtainMessage(JS_PROMPT, result);
- prompt.getData().putString("message", message);
- prompt.getData().putString("default", defaultValue);
- prompt.getData().putString("url", url);
- synchronized (this) {
- sendMessage(prompt);
- try {
- wait();
- } catch (InterruptedException e) {
- Log.e(LOGTAG, "Caught exception while waiting for jsPrompt");
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
- }
- return result.getStringResult();
- }
-
- public boolean onJsBeforeUnload(String url, String message) {
- // Do an unsynchronized quick check to avoid posting if no callback has
- // been set.
- if (mWebChromeClient == null) {
- return true;
- }
- JsResult result = new JsResult(this, true);
- Message confirm = obtainMessage(JS_UNLOAD, result);
- confirm.getData().putString("message", message);
- confirm.getData().putString("url", url);
- synchronized (this) {
- sendMessage(confirm);
- try {
- wait();
- } catch (InterruptedException e) {
- Log.e(LOGTAG, "Caught exception while waiting for jsUnload");
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
- }
- return result.getResult();
- }
-}
diff --git a/core/java/android/webkit/ContentLoader.java b/core/java/android/webkit/ContentLoader.java
deleted file mode 100644
index fb01c8c..0000000
--- a/core/java/android/webkit/ContentLoader.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2008 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.content.Context;
-import android.net.http.EventHandler;
-import android.net.http.Headers;
-import android.net.Uri;
-
-import java.io.File;
-import java.io.FileInputStream;
-
-/**
- * This class is a concrete implementation of StreamLoader that loads
- * "content:" URIs
- */
-class ContentLoader extends StreamLoader {
-
- private String mUrl;
- private Context mContext;
- private String mContentType;
-
- /**
- * Construct a ContentLoader with the specified content URI
- *
- * @param rawUrl "content:" url pointing to content to be loaded. This url
- * is the same url passed in to the WebView.
- * @param loadListener LoadListener to pass the content to
- * @param context Context to use to access the asset.
- */
- ContentLoader(String rawUrl, LoadListener loadListener, Context context) {
- super(loadListener);
- mContext = context;
-
- /* strip off mimetype */
- int mimeIndex = rawUrl.lastIndexOf('?');
- if (mimeIndex != -1) {
- mUrl = rawUrl.substring(0, mimeIndex);
- mContentType = rawUrl.substring(mimeIndex + 1);
- } else {
- mUrl = rawUrl;
- }
-
- }
-
- @Override
- protected boolean setupStreamAndSendStatus() {
- Uri uri = Uri.parse(mUrl);
- if (uri == null) {
- mHandler.error(
- EventHandler.FILE_NOT_FOUND_ERROR,
- mContext.getString(
- com.android.internal.R.string.httpErrorBadUrl) +
- " " + mUrl);
- return false;
- }
-
- try {
- mDataStream = mContext.getContentResolver().openInputStream(uri);
- mHandler.status(1, 1, 0, "OK");
- } catch (java.io.FileNotFoundException ex) {
- mHandler.error(
- EventHandler.FILE_NOT_FOUND_ERROR,
- mContext.getString(
- com.android.internal.R.string.httpErrorFileNotFound) +
- " " + ex.getMessage());
- return false;
-
- } catch (java.io.IOException ex) {
- mHandler.error(
- EventHandler.FILE_ERROR,
- mContext.getString(
- com.android.internal.R.string.httpErrorFileNotFound) +
- " " + ex.getMessage());
- return false;
- } catch (RuntimeException ex) {
- // readExceptionWithFileNotFoundExceptionFromParcel in DatabaseUtils
- // can throw a serial of RuntimeException. Catch them all here.
- mHandler.error(
- EventHandler.FILE_ERROR,
- mContext.getString(
- com.android.internal.R.string.httpErrorFileNotFound) +
- " " + ex.getMessage());
- return false;
- }
- return true;
- }
-
- @Override
- protected void buildHeaders(Headers headers) {
- if (mContentType != null) {
- headers.setContentType("text/html");
- }
- }
-
- /**
- * Construct a ContentLoader and instruct it to start loading.
- *
- * @param url "content:" url pointing to content to be loaded
- * @param loadListener LoadListener to pass the content to
- * @param context Context to use to access the asset.
- */
- public static void requestUrl(String url, LoadListener loadListener,
- Context context) {
- ContentLoader loader = new ContentLoader(url, loadListener, context);
- loader.load();
- }
-
-}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
deleted file mode 100644
index 07c1a5d..0000000
--- a/core/java/android/webkit/CookieManager.java
+++ /dev/null
@@ -1,934 +0,0 @@
-/*
- * 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.ParseException;
-import android.net.WebAddress;
-import android.util.Config;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * CookieManager manages cookies according to RFC2109 spec.
- */
-public final class CookieManager {
-
- private static CookieManager sRef;
-
- private static final String LOGTAG = "webkit";
-
- private static final String DOMAIN = "domain";
-
- private static final String PATH = "path";
-
- private static final String EXPIRES = "expires";
-
- private static final String SECURE = "secure";
-
- private static final String MAX_AGE = "max-age";
-
- private static final String HTTP_ONLY = "httponly";
-
- private static final String HTTPS = "https";
-
- private static final char PERIOD = '.';
-
- private static final char COMMA = ',';
-
- private static final char SEMICOLON = ';';
-
- private static final char EQUAL = '=';
-
- private static final char PATH_DELIM = '/';
-
- private static final char QUESTION_MARK = '?';
-
- private static final char WHITE_SPACE = ' ';
-
- private static final char QUOTATION = '\"';
-
- private static final int SECURE_LENGTH = SECURE.length();
-
- private static final int HTTP_ONLY_LENGTH = HTTP_ONLY.length();
-
- // RFC2109 defines 4k as maximum size of a cookie
- private static final int MAX_COOKIE_LENGTH = 4 * 1024;
-
- // RFC2109 defines 20 as max cookie count per domain. As we track with base
- // domain, we allow 50 per base domain
- private static final int MAX_COOKIE_COUNT_PER_BASE_DOMAIN = 50;
-
- // RFC2109 defines 300 as max count of domains. As we track with base
- // domain, we set 200 as max base domain count
- private static final int MAX_DOMAIN_COUNT = 200;
-
- // max cookie count to limit RAM cookie takes less than 100k, it is based on
- // average cookie entry size is less than 100 bytes
- private static final int MAX_RAM_COOKIES_COUNT = 1000;
-
- // max domain count to limit RAM cookie takes less than 100k,
- private static final int MAX_RAM_DOMAIN_COUNT = 15;
-
- private Map<String, ArrayList<Cookie>> mCookieMap = new LinkedHashMap
- <String, ArrayList<Cookie>>(MAX_DOMAIN_COUNT, 0.75f, true);
-
- private boolean mAcceptCookie = true;
-
- /**
- * This contains a list of 2nd-level domains that aren't allowed to have
- * wildcards when combined with country-codes. For example: [.co.uk].
- */
- private final static String[] BAD_COUNTRY_2LDS =
- { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
- "lg", "ne", "net", "or", "org" };
-
- static {
- Arrays.sort(BAD_COUNTRY_2LDS);
- }
-
- /**
- * Package level class to be accessed by cookie sync manager
- */
- static class Cookie {
- static final byte MODE_NEW = 0;
-
- static final byte MODE_NORMAL = 1;
-
- static final byte MODE_DELETED = 2;
-
- static final byte MODE_REPLACED = 3;
-
- String domain;
-
- String path;
-
- String name;
-
- String value;
-
- long expires;
-
- long lastAcessTime;
-
- long lastUpdateTime;
-
- boolean secure;
-
- byte mode;
-
- Cookie() {
- }
-
- Cookie(String defaultDomain, String defaultPath) {
- domain = defaultDomain;
- path = defaultPath;
- expires = -1;
- }
-
- boolean exactMatch(Cookie in) {
- return domain.equals(in.domain) && path.equals(in.path) &&
- name.equals(in.name);
- }
-
- boolean domainMatch(String urlHost) {
- if (domain.startsWith(".")) {
- if (urlHost.endsWith(domain.substring(1))) {
- int len = domain.length();
- int urlLen = urlHost.length();
- if (urlLen > len - 1) {
- // make sure bar.com doesn't match .ar.com
- return urlHost.charAt(urlLen - len) == PERIOD;
- }
- return true;
- }
- return false;
- } else {
- // exact match if domain is not leading w/ dot
- return urlHost.equals(domain);
- }
- }
-
- boolean pathMatch(String urlPath) {
- if (urlPath.startsWith(path)) {
- int len = path.length();
- if (len == 0) {
- Log.w(LOGTAG, "Empty cookie path");
- return false;
- }
- int urlLen = urlPath.length();
- if (path.charAt(len-1) != PATH_DELIM && urlLen > len) {
- // make sure /wee doesn't match /we
- return urlPath.charAt(len) == PATH_DELIM;
- }
- return true;
- }
- return false;
- }
-
- public String toString() {
- return "domain: " + domain + "; path: " + path + "; name: " + name
- + "; value: " + value;
- }
- }
-
- private CookieManager() {
- }
-
- protected Object clone() throws CloneNotSupportedException {
- throw new CloneNotSupportedException("doesn't implement Cloneable");
- }
-
- /**
- * Get a singleton CookieManager. If this is called before any
- * {@link WebView} is created or outside of {@link WebView} context, the
- * caller needs to call {@link CookieSyncManager#createInstance(Context)}
- * first.
- *
- * @return CookieManager
-= */
- public static synchronized CookieManager getInstance() {
- if (sRef == null) {
- sRef = new CookieManager();
- }
- return sRef;
- }
-
- /**
- * Control whether cookie is enabled or disabled
- * @param accept TRUE if accept cookie
- */
- public synchronized void setAcceptCookie(boolean accept) {
- mAcceptCookie = accept;
- }
-
- /**
- * Return whether cookie is enabled
- * @return TRUE if accept cookie
- */
- public synchronized boolean acceptCookie() {
- return mAcceptCookie;
- }
-
- /**
- * Set cookie for a given url. The old cookie with same host/path/name will
- * be removed. The new cookie will be added if it is not expired or it does
- * not have expiration which implies it is session cookie.
- * @param url The url which cookie is set for
- * @param value The value for set-cookie: in http response header
- */
- public void setCookie(String url, String value) {
- WebAddress uri;
- try {
- uri = new WebAddress(url);
- } catch (ParseException ex) {
- Log.e(LOGTAG, "Bad address: " + url);
- return;
- }
- setCookie(uri, value);
- }
-
- /**
- * Set cookie for a given uri. The old cookie with same host/path/name will
- * be removed. The new cookie will be added if it is not expired or it does
- * not have expiration which implies it is session cookie.
- * @param uri The uri which cookie is set for
- * @param value The value for set-cookie: in http response header
- * @hide - hide this because it takes in a parameter of type WebAddress,
- * a system private class.
- */
- public synchronized void setCookie(WebAddress uri, String value) {
- if (value != null && value.length() > MAX_COOKIE_LENGTH) {
- return;
- }
- if (!mAcceptCookie || uri == null) {
- return;
- }
- if (Config.LOGV) {
- Log.v(LOGTAG, "setCookie: uri: " + uri + " value: " + value);
- }
-
- String[] hostAndPath = getHostAndPath(uri);
- if (hostAndPath == null) {
- return;
- }
-
- // For default path, when setting a cookie, the spec says:
- //Path: Defaults to the path of the request URL that generated the
- // Set-Cookie response, up to, but not including, the
- // right-most /.
- if (hostAndPath[1].length() > 1) {
- int index = hostAndPath[1].lastIndexOf(PATH_DELIM);
- hostAndPath[1] = hostAndPath[1].substring(0,
- index > 0 ? index : index + 1);
- }
-
- ArrayList<Cookie> cookies = null;
- try {
- cookies = parseCookie(hostAndPath[0], hostAndPath[1], value);
- } catch (RuntimeException ex) {
- Log.e(LOGTAG, "parse cookie failed for: " + value);
- }
-
- if (cookies == null || cookies.size() == 0) {
- return;
- }
-
- String baseDomain = getBaseDomain(hostAndPath[0]);
- ArrayList<Cookie> cookieList = mCookieMap.get(baseDomain);
- if (cookieList == null) {
- cookieList = CookieSyncManager.getInstance()
- .getCookiesForDomain(baseDomain);
- mCookieMap.put(baseDomain, cookieList);
- }
-
- long now = System.currentTimeMillis();
- int size = cookies.size();
- for (int i = 0; i < size; i++) {
- Cookie cookie = cookies.get(i);
-
- boolean done = false;
- Iterator<Cookie> iter = cookieList.iterator();
- while (iter.hasNext()) {
- Cookie cookieEntry = iter.next();
- if (cookie.exactMatch(cookieEntry)) {
- // expires == -1 means no expires defined. Otherwise
- // negative means far future
- if (cookie.expires < 0 || cookie.expires > now) {
- // secure cookies can't be overwritten by non-HTTPS url
- if (!cookieEntry.secure || HTTPS.equals(uri.mScheme)) {
- cookieEntry.value = cookie.value;
- cookieEntry.expires = cookie.expires;
- cookieEntry.secure = cookie.secure;
- cookieEntry.lastAcessTime = now;
- cookieEntry.lastUpdateTime = now;
- cookieEntry.mode = Cookie.MODE_REPLACED;
- }
- } else {
- cookieEntry.lastUpdateTime = now;
- cookieEntry.mode = Cookie.MODE_DELETED;
- }
- done = true;
- break;
- }
- }
-
- // expires == -1 means no expires defined. Otherwise negative means
- // far future
- if (!done && (cookie.expires < 0 || cookie.expires > now)) {
- cookie.lastAcessTime = now;
- cookie.lastUpdateTime = now;
- cookie.mode = Cookie.MODE_NEW;
- if (cookieList.size() > MAX_COOKIE_COUNT_PER_BASE_DOMAIN) {
- Cookie toDelete = new Cookie();
- toDelete.lastAcessTime = now;
- Iterator<Cookie> iter2 = cookieList.iterator();
- while (iter2.hasNext()) {
- Cookie cookieEntry2 = iter2.next();
- if ((cookieEntry2.lastAcessTime < toDelete.lastAcessTime)
- && cookieEntry2.mode != Cookie.MODE_DELETED) {
- toDelete = cookieEntry2;
- }
- }
- toDelete.mode = Cookie.MODE_DELETED;
- }
- cookieList.add(cookie);
- }
- }
- }
-
- /**
- * Get cookie(s) for a given url so that it can be set to "cookie:" in http
- * request header.
- * @param url The url needs cookie
- * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
- */
- public String getCookie(String url) {
- WebAddress uri;
- try {
- uri = new WebAddress(url);
- } catch (ParseException ex) {
- Log.e(LOGTAG, "Bad address: " + url);
- return null;
- }
- return getCookie(uri);
- }
-
- /**
- * Get cookie(s) for a given uri so that it can be set to "cookie:" in http
- * request header.
- * @param uri The uri needs cookie
- * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
- * @hide - hide this because it has a parameter of type WebAddress, which
- * is a system private class.
- */
- public synchronized String getCookie(WebAddress uri) {
- if (!mAcceptCookie || uri == null) {
- return null;
- }
-
- String[] hostAndPath = getHostAndPath(uri);
- if (hostAndPath == null) {
- return null;
- }
-
- String baseDomain = getBaseDomain(hostAndPath[0]);
- ArrayList<Cookie> cookieList = mCookieMap.get(baseDomain);
- if (cookieList == null) {
- cookieList = CookieSyncManager.getInstance()
- .getCookiesForDomain(baseDomain);
- mCookieMap.put(baseDomain, cookieList);
- }
-
- long now = System.currentTimeMillis();
- boolean secure = HTTPS.equals(uri.mScheme);
- Iterator<Cookie> iter = cookieList.iterator();
- StringBuilder ret = new StringBuilder(256);
-
- while (iter.hasNext()) {
- Cookie cookie = iter.next();
- if (cookie.domainMatch(hostAndPath[0]) &&
- cookie.pathMatch(hostAndPath[1])
- // expires == -1 means no expires defined. Otherwise
- // negative means far future
- && (cookie.expires < 0 || cookie.expires > now)
- && (!cookie.secure || secure)
- && cookie.mode != Cookie.MODE_DELETED) {
- cookie.lastAcessTime = now;
-
- if (ret.length() > 0) {
- ret.append(SEMICOLON);
- // according to RC2109, SEMICOLON is office separator,
- // but when log in yahoo.com, it needs WHITE_SPACE too.
- ret.append(WHITE_SPACE);
- }
-
- ret.append(cookie.name);
- ret.append(EQUAL);
- ret.append(cookie.value);
- }
- }
- if (ret.length() > 0) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "getCookie: uri: " + uri + " value: " + ret);
- }
- return ret.toString();
- } else {
- if (Config.LOGV) {
- Log.v(LOGTAG, "getCookie: uri: " + uri
- + " But can't find cookie.");
- }
- return null;
- }
- }
-
- /**
- * Remove all session cookies, which are cookies without expiration date
- */
- public void removeSessionCookie() {
- final Runnable clearCache = new Runnable() {
- public void run() {
- synchronized(CookieManager.this) {
- Collection<ArrayList<Cookie>> cookieList = mCookieMap.values();
- Iterator<ArrayList<Cookie>> listIter = cookieList.iterator();
- while (listIter.hasNext()) {
- ArrayList<Cookie> list = listIter.next();
- Iterator<Cookie> iter = list.iterator();
- while (iter.hasNext()) {
- Cookie cookie = iter.next();
- if (cookie.expires == -1) {
- iter.remove();
- }
- }
- }
- CookieSyncManager.getInstance().clearSessionCookies();
- }
- }
- };
- new Thread(clearCache).start();
- }
-
- /**
- * Remove all cookies
- */
- public void removeAllCookie() {
- final Runnable clearCache = new Runnable() {
- public void run() {
- synchronized(CookieManager.this) {
- mCookieMap = new LinkedHashMap<String, ArrayList<Cookie>>(
- MAX_DOMAIN_COUNT, 0.75f, true);
- CookieSyncManager.getInstance().clearAllCookies();
- }
- }
- };
- new Thread(clearCache).start();
- }
-
- /**
- * Return true if there are stored cookies.
- */
- public synchronized boolean hasCookies() {
- return CookieSyncManager.getInstance().hasCookies();
- }
-
- /**
- * Remove all expired cookies
- */
- public void removeExpiredCookie() {
- final Runnable clearCache = new Runnable() {
- public void run() {
- synchronized(CookieManager.this) {
- long now = System.currentTimeMillis();
- Collection<ArrayList<Cookie>> cookieList = mCookieMap.values();
- Iterator<ArrayList<Cookie>> listIter = cookieList.iterator();
- while (listIter.hasNext()) {
- ArrayList<Cookie> list = listIter.next();
- Iterator<Cookie> iter = list.iterator();
- while (iter.hasNext()) {
- Cookie cookie = iter.next();
- // expires == -1 means no expires defined. Otherwise
- // negative means far future
- if (cookie.expires > 0 && cookie.expires < now) {
- iter.remove();
- }
- }
- }
- CookieSyncManager.getInstance().clearExpiredCookies(now);
- }
- }
- };
- new Thread(clearCache).start();
- }
-
- /**
- * Package level api, called from CookieSyncManager
- *
- * Get a list of cookies which are updated since a given time.
- * @param last The given time in millisec
- * @return A list of cookies
- */
- synchronized ArrayList<Cookie> getUpdatedCookiesSince(long last) {
- ArrayList<Cookie> cookies = new ArrayList<Cookie>();
- Collection<ArrayList<Cookie>> cookieList = mCookieMap.values();
- Iterator<ArrayList<Cookie>> listIter = cookieList.iterator();
- while (listIter.hasNext()) {
- ArrayList<Cookie> list = listIter.next();
- Iterator<Cookie> iter = list.iterator();
- while (iter.hasNext()) {
- Cookie cookie = iter.next();
- if (cookie.lastUpdateTime > last) {
- cookies.add(cookie);
- }
- }
- }
- return cookies;
- }
-
- /**
- * Package level api, called from CookieSyncManager
- *
- * Delete a Cookie in the RAM
- * @param cookie Cookie to be deleted
- */
- synchronized void deleteACookie(Cookie cookie) {
- if (cookie.mode == Cookie.MODE_DELETED) {
- String baseDomain = getBaseDomain(cookie.domain);
- ArrayList<Cookie> cookieList = mCookieMap.get(baseDomain);
- if (cookieList != null) {
- cookieList.remove(cookie);
- if (cookieList.isEmpty()) {
- mCookieMap.remove(baseDomain);
- }
- }
- }
- }
-
- /**
- * Package level api, called from CookieSyncManager
- *
- * Called after a cookie is synced to FLASH
- * @param cookie Cookie to be synced
- */
- synchronized void syncedACookie(Cookie cookie) {
- cookie.mode = Cookie.MODE_NORMAL;
- }
-
- /**
- * Package level api, called from CookieSyncManager
- *
- * Delete the least recent used domains if the total cookie count in RAM
- * exceeds the limit
- * @return A list of cookies which are removed from RAM
- */
- synchronized ArrayList<Cookie> deleteLRUDomain() {
- int count = 0;
- int byteCount = 0;
- int mapSize = mCookieMap.size();
-
- if (mapSize < MAX_RAM_DOMAIN_COUNT) {
- Collection<ArrayList<Cookie>> cookieLists = mCookieMap.values();
- Iterator<ArrayList<Cookie>> listIter = cookieLists.iterator();
- while (listIter.hasNext() && count < MAX_RAM_COOKIES_COUNT) {
- ArrayList<Cookie> list = listIter.next();
- if (Config.DEBUG) {
- Iterator<Cookie> iter = list.iterator();
- while (iter.hasNext() && count < MAX_RAM_COOKIES_COUNT) {
- Cookie cookie = iter.next();
- // 14 is 3 * sizeof(long) + sizeof(boolean)
- // + sizeof(byte)
- byteCount += cookie.domain.length()
- + cookie.path.length()
- + cookie.name.length()
- + cookie.value.length() + 14;
- count++;
- }
- } else {
- count += list.size();
- }
- }
- }
-
- ArrayList<Cookie> retlist = new ArrayList<Cookie>();
- if (mapSize >= MAX_RAM_DOMAIN_COUNT || count >= MAX_RAM_COOKIES_COUNT) {
- if (Config.DEBUG) {
- Log.v(LOGTAG, count + " cookies used " + byteCount
- + " bytes with " + mapSize + " domains");
- }
- Object[] domains = mCookieMap.keySet().toArray();
- int toGo = mapSize / 10 + 1;
- while (toGo-- > 0){
- String domain = domains[toGo].toString();
- if (Config.LOGV) {
- Log.v(LOGTAG, "delete domain: " + domain
- + " from RAM cache");
- }
- retlist.addAll(mCookieMap.get(domain));
- mCookieMap.remove(domain);
- }
- }
- return retlist;
- }
-
- /**
- * Extract the host and path out of a uri
- * @param uri The given WebAddress
- * @return The host and path in the format of String[], String[0] is host
- * which has at least two periods, String[1] is path which always
- * ended with "/"
- */
- private String[] getHostAndPath(WebAddress uri) {
- if (uri.mHost != null && uri.mPath != null) {
- String[] ret = new String[2];
- ret[0] = uri.mHost;
- ret[1] = uri.mPath;
-
- int index = ret[0].indexOf(PERIOD);
- if (index == -1) {
- if (uri.mScheme.equalsIgnoreCase("file")) {
- // There is a potential bug where a local file path matches
- // another file in the local web server directory. Still
- // "localhost" is the best pseudo domain name.
- ret[0] = "localhost";
- } else if (!ret[0].equals("localhost")) {
- return null;
- }
- } else if (index == ret[0].lastIndexOf(PERIOD)) {
- // cookie host must have at least two periods
- ret[0] = PERIOD + ret[0];
- }
-
- if (ret[1].charAt(0) != PATH_DELIM) {
- return null;
- }
-
- /*
- * find cookie path, e.g. for http://www.google.com, the path is "/"
- * for http://www.google.com/lab/, the path is "/lab"
- * for http://www.google.com/lab/foo, the path is "/lab/foo"
- * for http://www.google.com/lab?hl=en, the path is "/lab"
- * for http://www.google.com/lab.asp?hl=en, the path is "/lab.asp"
- * Note: the path from URI has at least one "/"
- * See:
- * http://www.unix.com.ua/rfc/rfc2109.html
- */
- index = ret[1].indexOf(QUESTION_MARK);
- if (index != -1) {
- ret[1] = ret[1].substring(0, index);
- }
- return ret;
- } else
- return null;
- }
-
- /**
- * Get the base domain for a give host. E.g. mail.google.com will return
- * google.com
- * @param host The give host
- * @return the base domain
- */
- private String getBaseDomain(String host) {
- int startIndex = 0;
- int nextIndex = host.indexOf(PERIOD);
- int lastIndex = host.lastIndexOf(PERIOD);
- while (nextIndex < lastIndex) {
- startIndex = nextIndex + 1;
- nextIndex = host.indexOf(PERIOD, startIndex);
- }
- if (startIndex > 0) {
- return host.substring(startIndex);
- } else {
- return host;
- }
- }
-
- /**
- * parseCookie() parses the cookieString which is a comma-separated list of
- * one or more cookies in the format of "NAME=VALUE; expires=DATE;
- * path=PATH; domain=DOMAIN_NAME; secure httponly" to a list of Cookies.
- * Here is a sample: IGDND=1, IGPC=ET=UB8TSNwtDmQ:AF=0; expires=Sun,
- * 17-Jan-2038 19:14:07 GMT; path=/ig; domain=.google.com, =,
- * PREF=ID=408909b1b304593d:TM=1156459854:LM=1156459854:S=V-vCAU6Sh-gobCfO;
- * expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com which
- * contains 3 cookies IGDND, IGPC, PREF and an empty cookie
- * @param host The default host
- * @param path The default path
- * @param cookieString The string coming from "Set-Cookie:"
- * @return A list of Cookies
- */
- private ArrayList<Cookie> parseCookie(String host, String path,
- String cookieString) {
- ArrayList<Cookie> ret = new ArrayList<Cookie>();
-
- int index = 0;
- int length = cookieString.length();
- while (true) {
- Cookie cookie = null;
-
- // done
- if (index < 0 || index >= length) {
- break;
- }
-
- // skip white space
- if (cookieString.charAt(index) == WHITE_SPACE) {
- index++;
- continue;
- }
-
- /*
- * get NAME=VALUE; pair. detecting the end of a pair is tricky, it
- * can be the end of a string, like "foo=bluh", it can be semicolon
- * like "foo=bluh;path=/"; or it can be enclosed by \", like
- * "foo=\"bluh bluh\";path=/"
- *
- * Note: in the case of "foo=bluh, bar=bluh;path=/", we interpret
- * it as one cookie instead of two cookies.
- */
- int equalIndex = cookieString.indexOf(EQUAL, index);
- if (equalIndex == -1) {
- // bad format, force return
- break;
- }
- cookie = new Cookie(host, path);
- cookie.name = cookieString.substring(index, equalIndex);
- if (cookieString.charAt(equalIndex + 1) == QUOTATION) {
- index = cookieString.indexOf(QUOTATION, equalIndex + 2);
- if (index == -1) {
- // bad format, force return
- break;
- }
- }
- int semicolonIndex = cookieString.indexOf(SEMICOLON, index);
- if (semicolonIndex == -1) {
- semicolonIndex = length;
- }
- if (semicolonIndex - equalIndex > MAX_COOKIE_LENGTH) {
- // cookie is too big, trim it
- cookie.value = cookieString.substring(equalIndex + 1,
- equalIndex + MAX_COOKIE_LENGTH);
- } else if (equalIndex + 1 == semicolonIndex
- || semicolonIndex < equalIndex) {
- // these are unusual case like foo=; and foo; path=/
- cookie.value = "";
- } else {
- cookie.value = cookieString.substring(equalIndex + 1,
- semicolonIndex);
- }
- // get attributes
- index = semicolonIndex;
- while (true) {
- // done
- if (index < 0 || index >= length) {
- break;
- }
-
- // skip white space and semicolon
- if (cookieString.charAt(index) == WHITE_SPACE
- || cookieString.charAt(index) == SEMICOLON) {
- index++;
- continue;
- }
-
- // comma means next cookie
- if (cookieString.charAt(index) == COMMA) {
- index++;
- break;
- }
-
- // "secure" is a known attribute doesn't use "=";
- // while sites like live.com uses "secure="
- if (length - index > SECURE_LENGTH
- && cookieString.substring(index, index + SECURE_LENGTH).
- equalsIgnoreCase(SECURE)) {
- index += SECURE_LENGTH;
- cookie.secure = true;
- if (cookieString.charAt(index) == EQUAL) index++;
- continue;
- }
-
- // "httponly" is a known attribute doesn't use "=";
- // while sites like live.com uses "httponly="
- if (length - index > HTTP_ONLY_LENGTH
- && cookieString.substring(index,
- index + HTTP_ONLY_LENGTH).
- equalsIgnoreCase(HTTP_ONLY)) {
- index += HTTP_ONLY_LENGTH;
- if (cookieString.charAt(index) == EQUAL) index++;
- // FIXME: currently only parse the attribute
- continue;
- }
- equalIndex = cookieString.indexOf(EQUAL, index);
- if (equalIndex > 0) {
- String name = cookieString.substring(index, equalIndex)
- .toLowerCase();
- if (name.equals(EXPIRES)) {
- int comaIndex = cookieString.indexOf(COMMA, equalIndex);
-
- // skip ',' in (Wdy, DD-Mon-YYYY HH:MM:SS GMT) or
- // (Weekday, DD-Mon-YY HH:MM:SS GMT) if it applies.
- // "Wednesday" is the longest Weekday which has length 9
- if ((comaIndex != -1) &&
- (comaIndex - equalIndex <= 10)) {
- index = comaIndex + 1;
- }
- }
- semicolonIndex = cookieString.indexOf(SEMICOLON, index);
- int commaIndex = cookieString.indexOf(COMMA, index);
- if (semicolonIndex == -1 && commaIndex == -1) {
- index = length;
- } else if (semicolonIndex == -1) {
- index = commaIndex;
- } else if (commaIndex == -1) {
- index = semicolonIndex;
- } else {
- index = Math.min(semicolonIndex, commaIndex);
- }
- String value =
- cookieString.substring(equalIndex + 1, index);
-
- // Strip quotes if they exist
- if (value.length() > 2 && value.charAt(0) == QUOTATION) {
- int endQuote = value.indexOf(QUOTATION, 1);
- if (endQuote > 0) {
- value = value.substring(1, endQuote);
- }
- }
- if (name.equals(EXPIRES)) {
- try {
- cookie.expires = HttpDateTime.parse(value);
- } catch (IllegalArgumentException ex) {
- Log.e(LOGTAG,
- "illegal format for expires: " + value);
- }
- } else if (name.equals(MAX_AGE)) {
- try {
- cookie.expires = System.currentTimeMillis() + 1000
- * Long.parseLong(value);
- } catch (NumberFormatException ex) {
- Log.e(LOGTAG,
- "illegal format for max-age: " + value);
- }
- } else if (name.equals(PATH)) {
- // only allow non-empty path value
- if (value.length() > 0) {
- cookie.path = value;
- }
- } else if (name.equals(DOMAIN)) {
- int lastPeriod = value.lastIndexOf(PERIOD);
- if (lastPeriod == 0) {
- // disallow cookies set for TLDs like [.com]
- cookie.domain = null;
- continue;
- }
- try {
- Integer.parseInt(value.substring(lastPeriod + 1));
- // no wildcard for ip address match
- if (!value.equals(host)) {
- // no cross-site cookie
- cookie.domain = null;
- }
- continue;
- } catch (NumberFormatException ex) {
- // ignore the exception, value is a host name
- }
- value = value.toLowerCase();
- if (value.charAt(0) != PERIOD) {
- // pre-pended dot to make it as a domain cookie
- value = PERIOD + value;
- lastPeriod++;
- }
- if (host.endsWith(value.substring(1))) {
- int len = value.length();
- int hostLen = host.length();
- if (hostLen > (len - 1)
- && host.charAt(hostLen - len) != PERIOD) {
- // make sure the bar.com doesn't match .ar.com
- cookie.domain = null;
- continue;
- }
- // disallow cookies set on ccTLDs like [.co.uk]
- if ((len == lastPeriod + 3)
- && (len >= 6 && len <= 8)) {
- String s = value.substring(1, lastPeriod);
- if (Arrays.binarySearch(BAD_COUNTRY_2LDS, s) >= 0) {
- cookie.domain = null;
- continue;
- }
- }
- cookie.domain = value;
- } else {
- // no cross-site or more specific sub-domain cookie
- cookie.domain = null;
- }
- }
- } else {
- // bad format, force return
- index = length;
- }
- }
- if (cookie != null && cookie.domain != null) {
- ret.add(cookie);
- }
- }
- return ret;
- }
-}
diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java
deleted file mode 100644
index f2511d8..0000000
--- a/core/java/android/webkit/CookieSyncManager.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2007 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.content.Context;
-import android.util.Config;
-import android.util.Log;
-import android.webkit.CookieManager.Cookie;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * The class CookieSyncManager is used to synchronize the browser cookies
- * between RAM and FLASH. To get the best performance, browser cookie is saved
- * in RAM. We use a separate thread to sync the cookies between RAM and FLASH on
- * a timer base.
- * <p>
- * To use the CookieSyncManager, the host application has to call the following
- * when the application starts.
- * <p>
- * CookieSyncManager.createInstance(context)
- * <p>
- * To set up for sync, the host application has to call
- * <p>
- * CookieSyncManager.getInstance().startSync()
- * <p>
- * in its Activity.onResume(), and call
- * <p>
- * CookieSyncManager.getInstance().stopSync()
- * <p>
- * in its Activity.onStop().
- * <p>
- * To get instant sync instead of waiting for the timer to trigger, the host can
- * call
- * <p>
- * CookieSyncManager.getInstance().sync()
- */
-public final class CookieSyncManager extends WebSyncManager {
-
- private static CookieSyncManager sRef;
-
- // time when last update happened
- private long mLastUpdate;
-
- private CookieSyncManager(Context context) {
- super(context, "CookieSyncManager");
- }
-
- /**
- * Singleton access to a {@link CookieSyncManager}. An
- * IllegalStateException will be thrown if
- * {@link CookieSyncManager#createInstance(Context)} is not called before.
- *
- * @return CookieSyncManager
- */
- public static synchronized CookieSyncManager getInstance() {
- if (sRef == null) {
- throw new IllegalStateException(
- "CookieSyncManager::createInstance() needs to be called "
- + "before CookieSyncManager::getInstance()");
- }
- return sRef;
- }
-
- /**
- * Create a singleton CookieSyncManager within a context
- * @param context
- * @return CookieSyncManager
- */
- public static synchronized CookieSyncManager createInstance(
- Context context) {
- if (sRef == null) {
- sRef = new CookieSyncManager(context);
- }
- return sRef;
- }
-
- /**
- * Package level api, called from CookieManager Get all the cookies which
- * matches a given base domain.
- * @param domain
- * @return A list of Cookie
- */
- ArrayList<Cookie> getCookiesForDomain(String domain) {
- // null mDataBase implies that the host application doesn't support
- // persistent cookie. No sync needed.
- if (mDataBase == null) {
- return new ArrayList<Cookie>();
- }
-
- return mDataBase.getCookiesForDomain(domain);
- }
-
- /**
- * Package level api, called from CookieManager Clear all cookies in the
- * database
- */
- void clearAllCookies() {
- // null mDataBase implies that the host application doesn't support
- // persistent cookie.
- if (mDataBase == null) {
- return;
- }
-
- mDataBase.clearCookies();
- }
-
- /**
- * Returns true if there are any saved cookies.
- */
- boolean hasCookies() {
- // null mDataBase implies that the host application doesn't support
- // persistent cookie.
- if (mDataBase == null) {
- return false;
- }
-
- return mDataBase.hasCookies();
- }
-
- /**
- * Package level api, called from CookieManager Clear all session cookies in
- * the database
- */
- void clearSessionCookies() {
- // null mDataBase implies that the host application doesn't support
- // persistent cookie.
- if (mDataBase == null) {
- return;
- }
-
- mDataBase.clearSessionCookies();
- }
-
- /**
- * Package level api, called from CookieManager Clear all expired cookies in
- * the database
- */
- void clearExpiredCookies(long now) {
- // null mDataBase implies that the host application doesn't support
- // persistent cookie.
- if (mDataBase == null) {
- return;
- }
-
- mDataBase.clearExpiredCookies(now);
- }
-
- protected void syncFromRamToFlash() {
- if (Config.LOGV) {
- Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash STARTS");
- }
-
- if (!CookieManager.getInstance().acceptCookie()) {
- return;
- }
-
- ArrayList<Cookie> cookieList = CookieManager.getInstance()
- .getUpdatedCookiesSince(mLastUpdate);
- mLastUpdate = System.currentTimeMillis();
- syncFromRamToFlash(cookieList);
-
- ArrayList<Cookie> lruList =
- CookieManager.getInstance().deleteLRUDomain();
- syncFromRamToFlash(lruList);
-
- if (Config.LOGV) {
- Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash DONE");
- }
- }
-
- private void syncFromRamToFlash(ArrayList<Cookie> list) {
- Iterator<Cookie> iter = list.iterator();
- while (iter.hasNext()) {
- Cookie cookie = iter.next();
- if (cookie.mode != Cookie.MODE_NORMAL) {
- if (cookie.mode != Cookie.MODE_NEW) {
- mDataBase.deleteCookies(cookie.domain, cookie.path,
- cookie.name);
- }
- if (cookie.mode != Cookie.MODE_DELETED) {
- mDataBase.addCookie(cookie);
- CookieManager.getInstance().syncedACookie(cookie);
- } else {
- CookieManager.getInstance().deleteACookie(cookie);
- }
- }
- }
- }
-}
diff --git a/core/java/android/webkit/DataLoader.java b/core/java/android/webkit/DataLoader.java
deleted file mode 100644
index dcdc949..0000000
--- a/core/java/android/webkit/DataLoader.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2007 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 org.apache.http.protocol.HTTP;
-
-import android.net.http.Headers;
-
-import java.io.ByteArrayInputStream;
-
-/**
- * This class is a concrete implementation of StreamLoader that uses the
- * content supplied as a URL as the source for the stream. The mimetype
- * optionally provided in the URL is extracted and inserted into the HTTP
- * response headers.
- */
-class DataLoader extends StreamLoader {
-
- private String mContentType; // Content mimetype, if supplied in URL
-
- /**
- * Constructor uses the dataURL as the source for an InputStream
- * @param dataUrl data: URL string optionally containing a mimetype
- * @param loadListener LoadListener to pass the content to
- */
- DataLoader(String dataUrl, LoadListener loadListener) {
- super(loadListener);
-
- String url = dataUrl.substring("data:".length());
- String content;
- int commaIndex = url.indexOf(',');
- if (commaIndex != -1) {
- mContentType = url.substring(0, commaIndex);
- content = url.substring(commaIndex + 1);
- } else {
- content = url;
- }
- mDataStream = new ByteArrayInputStream(content.getBytes());
- mContentLength = content.length();
- }
-
- @Override
- protected boolean setupStreamAndSendStatus() {
- mHandler.status(1, 1, 0, "OK");
- return true;
- }
-
- @Override
- protected void buildHeaders(Headers headers) {
- if (mContentType != null) {
- headers.setContentType(mContentType);
- }
- }
-
- /**
- * Construct a DataLoader and instruct it to start loading.
- *
- * @param url data: URL string optionally containing a mimetype
- * @param loadListener LoadListener to pass the content to
- */
- public static void requestUrl(String url, LoadListener loadListener) {
- DataLoader loader = new DataLoader(url, loadListener);
- loader.load();
- }
-
-}
diff --git a/core/java/android/webkit/DateSorter.java b/core/java/android/webkit/DateSorter.java
deleted file mode 100644
index 750403b..0000000
--- a/core/java/android/webkit/DateSorter.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.content.Context;
-import android.content.res.Resources;
-
-import java.util.Calendar;
-import java.util.Date;
-
-/**
- * Sorts dates into the following groups:
- * Today
- * Yesterday
- * five days ago
- * one month ago
- * older than a month ago
- */
-
-public class DateSorter {
-
- private static final String LOGTAG = "webkit";
-
- /** must be >= 3 */
- public static final int DAY_COUNT = 5;
-
- private long [] mBins = new long[DAY_COUNT];
- private String [] mLabels = new String[DAY_COUNT];
-
- private static final int NUM_DAYS_AGO = 5;
-
- Date mDate = new Date();
- Calendar mCal = Calendar.getInstance();
-
- /**
- * @param context Application context
- */
- public DateSorter(Context context) {
- Resources resources = context.getResources();
-
- Calendar c = Calendar.getInstance();
- beginningOfDay(c);
-
- // Create the bins
- mBins[0] = c.getTimeInMillis(); // Today
- c.roll(Calendar.DAY_OF_YEAR, -1);
- mBins[1] = c.getTimeInMillis(); // Yesterday
- c.roll(Calendar.DAY_OF_YEAR, -(NUM_DAYS_AGO - 1));
- mBins[2] = c.getTimeInMillis(); // Five days ago
- c.roll(Calendar.DAY_OF_YEAR, NUM_DAYS_AGO); // move back to today
- c.roll(Calendar.MONTH, -1);
- mBins[3] = c.getTimeInMillis(); // One month ago
- c.roll(Calendar.MONTH, -1);
- mBins[4] = c.getTimeInMillis(); // Over one month ago
-
- // build labels
- mLabels[0] = context.getText(com.android.internal.R.string.today).toString();
- mLabels[1] = context.getText(com.android.internal.R.string.yesterday).toString();
-
- int resId = com.android.internal.R.plurals.num_days_ago;
- String format = resources.getQuantityString(resId, NUM_DAYS_AGO);
- mLabels[2] = String.format(format, NUM_DAYS_AGO);
-
- mLabels[3] = context.getText(com.android.internal.R.string.oneMonthDurationPast).toString();
- mLabels[4] = context.getText(com.android.internal.R.string.beforeOneMonthDurationPast)
- .toString();
- }
-
- /**
- * @param time time since the Epoch in milliseconds, such as that
- * returned by Calendar.getTimeInMillis()
- * @return an index from 0 to (DAY_COUNT - 1) that identifies which
- * date bin this date belongs to
- */
- public int getIndex(long time) {
- // Lame linear search
- for (int i = 0; i < DAY_COUNT; i++) {
- if (time > mBins[i]) return i;
- }
- return DAY_COUNT - 1;
- }
-
- /**
- * @param index date bin index as returned by getIndex()
- * @return string label suitable for display to user
- */
- public String getLabel(int index) {
- return mLabels[index];
- }
-
-
- /**
- * @param index date bin index as returned by getIndex()
- * @return date boundary at given index
- */
- public long getBoundary(int index) {
- return mBins[index];
- }
-
- /**
- * Calcuate 12:00am by zeroing out hour, minute, second, millisecond
- */
- private Calendar beginningOfDay(Calendar c) {
- c.set(Calendar.HOUR_OF_DAY, 0);
- c.set(Calendar.MINUTE, 0);
- c.set(Calendar.SECOND, 0);
- c.set(Calendar.MILLISECOND, 0);
- return c;
- }
-}
diff --git a/core/java/android/webkit/DownloadListener.java b/core/java/android/webkit/DownloadListener.java
deleted file mode 100644
index dfaa1b9..0000000
--- a/core/java/android/webkit/DownloadListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2007 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;
-
-public interface DownloadListener {
-
- /**
- * Notify the host application that a file should be downloaded
- * @param url The full url to the content that should be downloaded
- * @param userAgent the user agent to be used for the download.
- * @param contentDisposition Content-disposition http header, if
- * present.
- * @param mimetype The mimetype of the content reported by the server
- * @param contentLength The file size reported by the server
- */
- public void onDownloadStart(String url, String userAgent,
- String contentDisposition, String mimetype, long contentLength);
-
-}
diff --git a/core/java/android/webkit/FileLoader.java b/core/java/android/webkit/FileLoader.java
deleted file mode 100644
index 54a4c1d..0000000
--- a/core/java/android/webkit/FileLoader.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2007 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 com.android.internal.R;
-
-import android.content.Context;
-import android.content.res.AssetManager;
-import android.net.http.EventHandler;
-import android.net.http.Headers;
-import android.os.Environment;
-
-import java.io.File;
-import java.io.FileInputStream;
-
-/**
- * This class is a concrete implementation of StreamLoader that uses a
- * file or asset as the source for the stream.
- *
- */
-class FileLoader extends StreamLoader {
-
- private String mPath; // Full path to the file to load
- private Context mContext; // Application context, used for asset loads
- private boolean mIsAsset; // Indicates if the load is an asset or not
- private boolean mAllowFileAccess; // Allow/block file system access
-
- /**
- * Construct a FileLoader with the file URL specified as the content
- * source.
- *
- * @param url Full file url pointing to content to be loaded
- * @param loadListener LoadListener to pass the content to
- * @param context Context to use to access the asset.
- * @param asset true if url points to an asset.
- * @param allowFileAccess true if this WebView is allowed to access files
- * on the file system.
- */
- FileLoader(String url, LoadListener loadListener, Context context,
- boolean asset, boolean allowFileAccess) {
- super(loadListener);
- mIsAsset = asset;
- mContext = context;
- mAllowFileAccess = allowFileAccess;
-
- // clean the Url
- int index = url.indexOf('?');
- if (mIsAsset) {
- mPath = index > 0 ? URLUtil.stripAnchor(
- url.substring(URLUtil.ASSET_BASE.length(), index)) :
- URLUtil.stripAnchor(url.substring(
- URLUtil.ASSET_BASE.length()));
- } else {
- mPath = index > 0 ? URLUtil.stripAnchor(
- url.substring(URLUtil.FILE_BASE.length(), index)) :
- URLUtil.stripAnchor(url.substring(
- URLUtil.FILE_BASE.length()));
- }
- }
-
- @Override
- protected boolean setupStreamAndSendStatus() {
- try {
- if (mIsAsset) {
- try {
- mDataStream = mContext.getAssets().open(mPath);
- } catch (java.io.FileNotFoundException ex) {
- // try the rest files included in the package
- mDataStream = mContext.getAssets().openNonAsset(mPath);
- }
- } else {
- if (!mAllowFileAccess) {
- mHandler.error(EventHandler.FILE_ERROR,
- mContext.getString(R.string.httpErrorFileNotFound));
- return false;
- }
-
- mDataStream = new FileInputStream(mPath);
- mContentLength = (new File(mPath)).length();
- }
- mHandler.status(1, 1, 0, "OK");
-
- } catch (java.io.FileNotFoundException ex) {
- mHandler.error(
- EventHandler.FILE_NOT_FOUND_ERROR,
- mContext.getString(R.string.httpErrorFileNotFound) +
- " " + ex.getMessage());
- return false;
-
- } catch (java.io.IOException ex) {
- mHandler.error(EventHandler.FILE_ERROR,
- mContext.getString(R.string.httpErrorFileNotFound) +
- " " + ex.getMessage());
- return false;
- }
- return true;
- }
-
- @Override
- protected void buildHeaders(Headers headers) {
- // do nothing.
- }
-
-
- /**
- * Construct a FileLoader and instruct it to start loading.
- *
- * @param url Full file url pointing to content to be loaded
- * @param loadListener LoadListener to pass the content to
- * @param context Context to use to access the asset.
- * @param asset true if url points to an asset.
- * @param allowFileAccess true if this FileLoader can load files from the
- * file system.
- */
- public static void requestUrl(String url, LoadListener loadListener,
- Context context, boolean asset, boolean allowFileAccess) {
- FileLoader loader = new FileLoader(url, loadListener, context, asset,
- allowFileAccess);
- loader.load();
- }
-
-}
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
deleted file mode 100644
index 5e323eb..0000000
--- a/core/java/android/webkit/FrameLoader.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * 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.http.EventHandler;
-import android.net.http.RequestHandle;
-import android.util.Config;
-import android.util.Log;
-import android.webkit.CacheManager.CacheResult;
-import android.webkit.UrlInterceptRegistry;
-
-import java.util.HashMap;
-import java.util.Map;
-
-class FrameLoader {
-
- private final LoadListener mListener;
- private final String mMethod;
- private final boolean mIsHighPriority;
- private final WebSettings mSettings;
- private Map<String, String> mHeaders;
- private byte[] mPostData;
- private Network mNetwork;
- private int mCacheMode;
- private String mReferrer;
- private String mContentType;
-
- private static final int URI_PROTOCOL = 0x100;
-
- private static final String CONTENT_TYPE = "content-type";
-
- // Contents of an about:blank page
- private static final String mAboutBlank =
- "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EB\">" +
- "<html><head><title>about:blank</title></head><body></body></html>";
-
- static final String HEADER_STR = "text/xml, text/html, " +
- "application/xhtml+xml, image/png, text/plain, */*;q=0.8";
-
- private static final String LOGTAG = "webkit";
-
- FrameLoader(LoadListener listener, WebSettings settings,
- String method, boolean highPriority) {
- mListener = listener;
- mHeaders = null;
- mMethod = method;
- mIsHighPriority = highPriority;
- mCacheMode = WebSettings.LOAD_NORMAL;
- mSettings = settings;
- }
-
- public void setReferrer(String ref) {
- // only set referrer for http or https
- if (URLUtil.isNetworkUrl(ref)) mReferrer = ref;
- }
-
- public void setPostData(byte[] postData) {
- mPostData = postData;
- }
-
- public void setContentTypeForPost(String postContentType) {
- mContentType = postContentType;
- }
-
- public void setCacheMode(int cacheMode) {
- mCacheMode = cacheMode;
- }
-
- public void setHeaders(HashMap headers) {
- mHeaders = headers;
- }
-
- public LoadListener getLoadListener() {
- return mListener;
- }
-
- /**
- * Issues the load request.
- *
- * Return value does not indicate if the load was successful or not. It
- * simply indicates that the load request is reasonable.
- *
- * @return true if the load is reasonable.
- */
- public boolean executeLoad() {
- String url = mListener.url();
-
- // Attempt to decode the percent-encoded url.
- try {
- url = new String(URLUtil.decode(url.getBytes()));
- } catch (IllegalArgumentException e) {
- // Fail with a bad url error if the decode fails.
- mListener.error(EventHandler.ERROR_BAD_URL,
- mListener.getContext().getString(
- com.android.internal.R.string.httpErrorBadUrl));
- return false;
- }
-
- if (URLUtil.isNetworkUrl(url)){
- if (mSettings.getBlockNetworkLoads()) {
- mListener.error(EventHandler.ERROR_BAD_URL,
- mListener.getContext().getString(
- com.android.internal.R.string.httpErrorBadUrl));
- return false;
- }
- mNetwork = Network.getInstance(mListener.getContext());
- return handleHTTPLoad();
- } else if (handleLocalFile(url, mListener, mSettings)) {
- return true;
- }
- if (Config.LOGV) {
- Log.v(LOGTAG, "FrameLoader.executeLoad: url protocol not supported:"
- + mListener.url());
- }
- mListener.error(EventHandler.ERROR_UNSUPPORTED_SCHEME,
- mListener.getContext().getText(
- com.android.internal.R.string.httpErrorUnsupportedScheme).toString());
- return false;
-
- }
-
- /* package */
- static boolean handleLocalFile(String url, LoadListener loadListener,
- WebSettings settings) {
- if (URLUtil.isAssetUrl(url)) {
- FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
- true, settings.getAllowFileAccess());
- return true;
- } else if (URLUtil.isFileUrl(url)) {
- FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
- false, settings.getAllowFileAccess());
- return true;
- } else if (URLUtil.isContentUrl(url)) {
- // Send the raw url to the ContentLoader because it will do a
- // permission check and the url has to match..
- ContentLoader.requestUrl(loadListener.url(), loadListener,
- loadListener.getContext());
- return true;
- } else if (URLUtil.isDataUrl(url)) {
- DataLoader.requestUrl(url, loadListener);
- return true;
- } else if (URLUtil.isAboutUrl(url)) {
- loadListener.data(mAboutBlank.getBytes(), mAboutBlank.length());
- loadListener.endData();
- return true;
- }
- return false;
- }
-
- private boolean handleHTTPLoad() {
- if (mHeaders == null) {
- mHeaders = new HashMap<String, String>();
- }
- populateStaticHeaders();
- populateHeaders();
-
- // response was handled by UrlIntercept, don't issue HTTP request
- if (handleUrlIntercept()) return true;
-
- // response was handled by Cache, don't issue HTTP request
- if (handleCache()) {
- // push the request data down to the LoadListener
- // as response from the cache could be a redirect
- // and we may need to initiate a network request if the cache
- // can't satisfy redirect URL
- mListener.setRequestData(mMethod, mHeaders, mPostData,
- mIsHighPriority);
- return true;
- }
-
- if (Config.LOGV) {
- Log.v(LOGTAG, "FrameLoader: http " + mMethod + " load for: "
- + mListener.url());
- }
-
- boolean ret = false;
- int error = EventHandler.ERROR_UNSUPPORTED_SCHEME;
-
- try {
- ret = mNetwork.requestURL(mMethod, mHeaders,
- mPostData, mListener, mIsHighPriority);
- } catch (android.net.ParseException ex) {
- error = EventHandler.ERROR_BAD_URL;
- } catch (java.lang.RuntimeException ex) {
- /* probably an empty header set by javascript. We want
- the same result as bad URL */
- error = EventHandler.ERROR_BAD_URL;
- }
- if (!ret) {
- mListener.error(error, mListener.getContext().getText(
- EventHandler.errorStringResources[Math.abs(error)]).toString());
- return false;
- }
- return true;
- }
-
- /*
- * This function is used by handleUrlInterecpt and handleCache to
- * setup a load from the byte stream in a CacheResult.
- */
- private void startCacheLoad(CacheResult result) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "FrameLoader: loading from cache: "
- + mListener.url());
- }
- // Tell the Listener respond with the cache file
- CacheLoader cacheLoader =
- new CacheLoader(mListener, result);
- mListener.setCacheLoader(cacheLoader);
- cacheLoader.load();
- }
-
- /*
- * This function is used by handleHTTPLoad to allow URL
- * interception. This can be used to provide alternative load
- * methods such as locally stored versions or for debugging.
- *
- * Returns true if the response was handled by UrlIntercept.
- */
- private boolean handleUrlIntercept() {
- // Check if the URL can be served from UrlIntercept. If
- // successful, return the data just like a cache hit.
- CacheResult result = UrlInterceptRegistry.getSurrogate(
- mListener.url(), mHeaders);
- if(result != null) {
- // Intercepted. The data is stored in result.stream. Setup
- // a load from the CacheResult.
- startCacheLoad(result);
- return true;
- }
- // Not intercepted. Carry on as normal.
- return false;
- }
-
- /*
- * This function is used by the handleHTTPLoad to setup the cache headers
- * correctly.
- * Returns true if the response was handled from the cache
- */
- private boolean handleCache() {
- switch (mCacheMode) {
- // This mode is normally used for a reload, it instructs the http
- // loader to not use the cached content.
- case WebSettings.LOAD_NO_CACHE:
- break;
-
-
- // This mode is used when the content should only be loaded from
- // the cache. If it is not there, then fail the load. This is used
- // to load POST content in a history navigation.
- case WebSettings.LOAD_CACHE_ONLY: {
- CacheResult result = CacheManager.getCacheFile(mListener.url(),
- null);
- if (result != null) {
- startCacheLoad(result);
- } else {
- // This happens if WebCore was first told that the POST
- // response was in the cache, then when we try to use it
- // it has gone.
- // Generate a file not found error
- int err = EventHandler.FILE_NOT_FOUND_ERROR;
- mListener.error(err, mListener.getContext().getText(
- EventHandler.errorStringResources[Math.abs(err)])
- .toString());
- }
- return true;
- }
-
- // This mode is for when the user is doing a history navigation
- // in the browser and should returned cached content regardless
- // of it's state. If it is not in the cache, then go to the
- // network.
- case WebSettings.LOAD_CACHE_ELSE_NETWORK: {
- if (Config.LOGV) {
- Log.v(LOGTAG, "FrameLoader: checking cache: "
- + mListener.url());
- }
- // Get the cache file name for the current URL, passing null for
- // the validation headers causes no validation to occur
- CacheResult result = CacheManager.getCacheFile(mListener.url(),
- null);
- if (result != null) {
- startCacheLoad(result);
- return true;
- }
- break;
- }
-
- // This is the default case, which is to check to see if the
- // content in the cache can be used. If it can be used, then
- // use it. If it needs revalidation then the relevant headers
- // are added to the request.
- default:
- case WebSettings.LOAD_NORMAL:
- return mListener.checkCache(mHeaders);
- }// end of switch
-
- return false;
- }
-
- /**
- * Add the static headers that don't change with each request.
- */
- private void populateStaticHeaders() {
- // Accept header should already be there as they are built by WebCore,
- // but in the case they are missing, add some.
- String accept = mHeaders.get("Accept");
- if (accept == null || accept.length() == 0) {
- mHeaders.put("Accept", HEADER_STR);
- }
- mHeaders.put("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");
-
- String acceptLanguage = mSettings.getAcceptLanguage();
- if (acceptLanguage.length() > 0) {
- mHeaders.put("Accept-Language", acceptLanguage);
- }
-
- mHeaders.put("User-Agent", mSettings.getUserAgentString());
- }
-
- /**
- * Add the content related headers. These headers contain user private data
- * and is not used when we are proxying an untrusted request.
- */
- private void populateHeaders() {
-
- if (mReferrer != null) mHeaders.put("Referer", mReferrer);
- if (mContentType != null) mHeaders.put(CONTENT_TYPE, mContentType);
-
- // if we have an active proxy and have proxy credentials, do pre-emptive
- // authentication to avoid an extra round-trip:
- if (mNetwork.isValidProxySet()) {
- String username;
- String password;
- /* The proxy credentials can be set in the Network thread */
- synchronized (mNetwork) {
- username = mNetwork.getProxyUsername();
- password = mNetwork.getProxyPassword();
- }
- if (username != null && password != null) {
- // we collect credentials ONLY if the proxy scheme is BASIC!!!
- String proxyHeader = RequestHandle.authorizationHeader(true);
- mHeaders.put(proxyHeader,
- "Basic " + RequestHandle.computeBasicAuthResponse(
- username, password));
- }
- }
-
- // Set cookie header
- String cookie = CookieManager.getInstance().getCookie(
- mListener.getWebAddress());
- if (cookie != null && cookie.length() > 0) {
- mHeaders.put("cookie", cookie);
- }
- }
-}
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java
deleted file mode 100644
index 48b9eec..0000000
--- a/core/java/android/webkit/HttpAuthHandler.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-
-import java.util.ListIterator;
-import java.util.LinkedList;
-
-/**
- * HTTP authentication handler: local handler that takes care
- * of HTTP authentication requests. This class is passed as a
- * parameter to BrowserCallback.displayHttpAuthDialog and is
- * meant to receive the user's response.
- */
-public class HttpAuthHandler extends Handler {
- /* It is important that the handler is in Network, because
- * we want to share it accross multiple loaders and windows
- * (like our subwindow and the main window).
- */
-
- private static final String LOGTAG = "network";
-
- /**
- * Network.
- */
- private Network mNetwork;
-
- /**
- * Loader queue.
- */
- private LinkedList<LoadListener> mLoaderQueue;
-
-
- // Message id for handling the user response
- private final int AUTH_PROCEED = 100;
- private final int AUTH_CANCEL = 200;
-
- /**
- * Creates a new HTTP authentication handler with an empty
- * loader queue
- *
- * @param network The parent network object
- */
- /* package */ HttpAuthHandler(Network network) {
- mNetwork = network;
- mLoaderQueue = new LinkedList<LoadListener>();
- }
-
-
- @Override
- public void handleMessage(Message msg) {
- LoadListener loader = null;
- synchronized (mLoaderQueue) {
- loader = mLoaderQueue.poll();
- }
-
- switch (msg.what) {
- case AUTH_PROCEED:
- String username = msg.getData().getString("username");
- String password = msg.getData().getString("password");
-
- loader.handleAuthResponse(username, password);
- break;
-
- case AUTH_CANCEL:
-
- mNetwork.resetHandlersAndStopLoading(loader.getFrame());
- break;
- }
-
- processNextLoader();
- }
-
-
- /**
- * Proceed with the authorization with the given credentials
- *
- * @param username The username to use for authentication
- * @param password The password to use for authentication
- */
- public void proceed(String username, String password) {
- Message msg = obtainMessage(AUTH_PROCEED);
- msg.getData().putString("username", username);
- msg.getData().putString("password", password);
- sendMessage(msg);
- }
-
- /**
- * Cancel the authorization request
- */
- public void cancel() {
- sendMessage(obtainMessage(AUTH_CANCEL));
- }
-
- /**
- * @return True if we can use user credentials on record
- * (ie, if we did not fail trying to use them last time)
- */
- public boolean useHttpAuthUsernamePassword() {
- LoadListener loader = null;
- synchronized (mLoaderQueue) {
- loader = mLoaderQueue.peek();
- }
- if (loader != null) {
- return !loader.authCredentialsInvalid();
- }
-
- return false;
- }
-
- /**
- * Resets the HTTP-authentication request handler, removes
- * all loaders that share the same BrowserFrame
- *
- * @param frame The browser frame
- */
- /* package */ void reset(BrowserFrame frame) {
- synchronized (mLoaderQueue) {
- ListIterator<LoadListener> i = mLoaderQueue.listIterator(0);
- while (i.hasNext()) {
- LoadListener loader = i.next();
- if (frame == loader.getFrame()) {
- i.remove();
- }
- }
- }
- }
-
- /**
- * Enqueues the loader, if the loader is the only element
- * in the queue, starts processing the loader
- *
- * @param loader The loader that resulted in this http
- * authentication request
- */
- /* package */ void handleAuthRequest(LoadListener loader) {
- boolean processNext = false;
-
- synchronized (mLoaderQueue) {
- mLoaderQueue.offer(loader);
- processNext =
- (mLoaderQueue.size() == 1);
- }
-
- if (processNext) {
- processNextLoader();
- }
- }
-
- /**
- * Process the next loader in the queue (helper method)
- */
- private void processNextLoader() {
- LoadListener loader = null;
- synchronized (mLoaderQueue) {
- loader = mLoaderQueue.peek();
- }
- if (loader != null) {
- CallbackProxy proxy = loader.getFrame().getCallbackProxy();
-
- String hostname = loader.proxyAuthenticate() ?
- mNetwork.getProxyHostname() : loader.host();
-
- String realm = loader.realm();
-
- proxy.onReceivedHttpAuthRequest(this, hostname, realm);
- }
- }
-}
diff --git a/core/java/android/webkit/HttpDateTime.java b/core/java/android/webkit/HttpDateTime.java
deleted file mode 100644
index c6ec2d2..0000000
--- a/core/java/android/webkit/HttpDateTime.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2007 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.text.format.Time;
-
-import java.util.Calendar;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-
-class HttpDateTime {
-
- /*
- * Regular expression for parsing HTTP-date.
- *
- * Wdy, DD Mon YYYY HH:MM:SS GMT
- * RFC 822, updated by RFC 1123
- *
- * Weekday, DD-Mon-YY HH:MM:SS GMT
- * RFC 850, obsoleted by RFC 1036
- *
- * Wdy Mon DD HH:MM:SS YYYY
- * ANSI C's asctime() format
- *
- * with following variations
- *
- * Wdy, DD-Mon-YYYY HH:MM:SS GMT
- * Wdy, (SP)D Mon YYYY HH:MM:SS GMT
- * Wdy,DD Mon YYYY HH:MM:SS GMT
- * Wdy, DD-Mon-YY HH:MM:SS GMT
- * Wdy, DD Mon YYYY HH:MM:SS -HHMM
- * Wdy, DD Mon YYYY HH:MM:SS
- * Wdy Mon (SP)D HH:MM:SS YYYY
- * Wdy Mon DD HH:MM:SS YYYY GMT
- */
- private static final String HTTP_DATE_RFC_REGEXP =
- "([0-9]{1,2})[- ]([A-Za-z]{3,3})[- ]([0-9]{2,4})[ ]"
- + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])";
-
- private static final String HTTP_DATE_ANSIC_REGEXP =
- "[ ]([A-Za-z]{3,3})[ ]+([0-9]{1,2})[ ]"
- + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
-
- /**
- * The compiled version of the HTTP-date regular expressions.
- */
- private static final Pattern HTTP_DATE_RFC_PATTERN =
- Pattern.compile(HTTP_DATE_RFC_REGEXP);
- private static final Pattern HTTP_DATE_ANSIC_PATTERN =
- Pattern.compile(HTTP_DATE_ANSIC_REGEXP);
-
- private static class TimeOfDay {
- int hour;
- int minute;
- int second;
- }
-
- public static Long parse(String timeString)
- throws IllegalArgumentException {
-
- int date = 1;
- int month = Calendar.JANUARY;
- int year = 1970;
- TimeOfDay timeOfDay = new TimeOfDay();
-
- Matcher rfcMatcher = HTTP_DATE_RFC_PATTERN.matcher(timeString);
- if (rfcMatcher.find()) {
- date = getDate(rfcMatcher.group(1));
- month = getMonth(rfcMatcher.group(2));
- year = getYear(rfcMatcher.group(3));
- timeOfDay = getTime(rfcMatcher.group(4));
- } else {
- Matcher ansicMatcher = HTTP_DATE_ANSIC_PATTERN.matcher(timeString);
- if (ansicMatcher.find()) {
- month = getMonth(ansicMatcher.group(1));
- date = getDate(ansicMatcher.group(2));
- timeOfDay = getTime(ansicMatcher.group(3));
- year = getYear(ansicMatcher.group(4));
- } else {
- throw new IllegalArgumentException();
- }
- }
-
- // FIXME: Y2038 BUG!
- if (year >= 2038) {
- year = 2038;
- month = Calendar.JANUARY;
- date = 1;
- }
-
- Time time = new Time(Time.TIMEZONE_UTC);
- time.set(timeOfDay.second, timeOfDay.minute, timeOfDay.hour, date,
- month, year);
- return time.toMillis(false /* use isDst */);
- }
-
- private static int getDate(String dateString) {
- if (dateString.length() == 2) {
- return (dateString.charAt(0) - '0') * 10
- + (dateString.charAt(1) - '0');
- } else {
- return (dateString.charAt(0) - '0');
- }
- }
-
- /*
- * jan = 9 + 0 + 13 = 22
- * feb = 5 + 4 + 1 = 10
- * mar = 12 + 0 + 17 = 29
- * apr = 0 + 15 + 17 = 32
- * may = 12 + 0 + 24 = 36
- * jun = 9 + 20 + 13 = 42
- * jul = 9 + 20 + 11 = 40
- * aug = 0 + 20 + 6 = 26
- * sep = 18 + 4 + 15 = 37
- * oct = 14 + 2 + 19 = 35
- * nov = 13 + 14 + 21 = 48
- * dec = 3 + 4 + 2 = 9
- */
- private static int getMonth(String monthString) {
- int hash = Character.toLowerCase(monthString.charAt(0)) +
- Character.toLowerCase(monthString.charAt(1)) +
- Character.toLowerCase(monthString.charAt(2)) - 3 * 'a';
- switch (hash) {
- case 22:
- return Calendar.JANUARY;
- case 10:
- return Calendar.FEBRUARY;
- case 29:
- return Calendar.MARCH;
- case 32:
- return Calendar.APRIL;
- case 36:
- return Calendar.MAY;
- case 42:
- return Calendar.JUNE;
- case 40:
- return Calendar.JULY;
- case 26:
- return Calendar.AUGUST;
- case 37:
- return Calendar.SEPTEMBER;
- case 35:
- return Calendar.OCTOBER;
- case 48:
- return Calendar.NOVEMBER;
- case 9:
- return Calendar.DECEMBER;
- default:
- throw new IllegalArgumentException();
- }
- }
-
- private static int getYear(String yearString) {
- if (yearString.length() == 2) {
- int year = (yearString.charAt(0) - '0') * 10
- + (yearString.charAt(1) - '0');
- if (year >= 70) {
- return year + 1900;
- } else {
- return year + 2000;
- }
- } else
- return (yearString.charAt(0) - '0') * 1000
- + (yearString.charAt(1) - '0') * 100
- + (yearString.charAt(2) - '0') * 10
- + (yearString.charAt(3) - '0');
- }
-
- private static TimeOfDay getTime(String timeString) {
- TimeOfDay time = new TimeOfDay();
- time.hour = (timeString.charAt(0) - '0') * 10
- + (timeString.charAt(1) - '0');
- time.minute = (timeString.charAt(3) - '0') * 10
- + (timeString.charAt(4) - '0');
- time.second = (timeString.charAt(6) - '0') * 10
- + (timeString.charAt(7) - '0');
- return time;
- }
-}
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
deleted file mode 100644
index a0049ac..0000000
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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.os.Handler;
-import android.os.Message;
-import android.util.Config;
-import android.util.Log;
-
-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;
- // Reference count the pause/resume of timers
- private int mPauseTimerRefCount;
-
- /**
- * Construct a new JWebCoreJavaBridge to interface with
- * WebCore timers and cookies.
- */
- public JWebCoreJavaBridge() {
- nativeConstructor();
- }
-
- @Override
- protected void finalize() {
- nativeFinalize();
- }
-
- /**
- * 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: {
- PerfChecker checker = new PerfChecker();
- // clear the flag so that sharedTimerFired() can set a new timer
- mHasInstantTimer = false;
- sharedTimerFired();
- checker.responseAlert("sharedTimer");
- break;
- }
- case FUNCPTR_MESSAGE:
- nativeServiceFuncPtrQueue();
- 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 (--mPauseTimerRefCount == 0) {
- setDeferringTimers(true);
- }
- }
-
- /**
- * Resume all timers.
- */
- public void resume() {
- if (++mPauseTimerRefCount == 1) {
- setDeferringTimers(false);
- }
- }
-
- /**
- * 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 docUrl The policy base url used by WebCore.
- * @param value The cookie string to be stored.
- */
- private void setCookies(String url, String docUrl, 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();
- }
-
- /**
- * setSharedTimer
- * @param timemillis The relative time when the timer should fire
- */
- private void setSharedTimer(long timemillis) {
- if (Config.LOGV) 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 (Config.LOGV) {
- Log.v(LOGTAG, "stopSharedTimer removing all timers");
- }
- removeMessages(TIMER_MESSAGE);
- mHasInstantTimer = false;
- }
-
- private native void nativeConstructor();
- private native void nativeFinalize();
- private native void sharedTimerFired();
- private native void setDeferringTimers(boolean defer);
- public native void setNetworkOnLine(boolean online);
-}
diff --git a/core/java/android/webkit/JsPromptResult.java b/core/java/android/webkit/JsPromptResult.java
deleted file mode 100644
index 9fcd1bc..0000000
--- a/core/java/android/webkit/JsPromptResult.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2007 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;
-
-
-/**
- * Public class for handling javascript prompt requests. A
- * JsDialogHandlerInterface implentation will receive a jsPrompt call with a
- * JsPromptResult parameter. This parameter is used to return a result to
- * WebView. The client can call cancel() to cancel the dialog or confirm() with
- * the user's input to confirm the dialog.
- */
-public class JsPromptResult extends JsResult {
- // String result of the prompt
- private String mStringResult;
-
- /**
- * Handle a confirmation response from the user.
- */
- public void confirm(String result) {
- mStringResult = result;
- confirm();
- }
-
- /*package*/ JsPromptResult(CallbackProxy proxy) {
- super(proxy, /* unused */ false);
- }
-
- /*package*/ String getStringResult() {
- return mStringResult;
- }
-
- @Override
- /*package*/ void handleDefault() {
- mStringResult = null;
- super.handleDefault();
- }
-}
diff --git a/core/java/android/webkit/JsResult.java b/core/java/android/webkit/JsResult.java
deleted file mode 100644
index 0c86e0a..0000000
--- a/core/java/android/webkit/JsResult.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2007 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;
-
-
-public class JsResult {
- // This prevents a user from interacting with the result before WebCore is
- // ready to handle it.
- private boolean mReady;
- // Tells us if the user tried to confirm or cancel the result before WebCore
- // is ready.
- private boolean mTriedToNotifyBeforeReady;
- // This is a basic result of a confirm or prompt dialog.
- protected boolean mResult;
- // This is the caller of the prompt and is the object that is waiting.
- protected final CallbackProxy mProxy;
- // This is the default value of the result.
- private final boolean mDefaultValue;
-
- /**
- * Handle the result if the user cancelled the dialog.
- */
- public final void cancel() {
- mResult = false;
- wakeUp();
- }
-
- /**
- * Handle a confirmation response from the user.
- */
- public final void confirm() {
- mResult = true;
- wakeUp();
- }
-
- /*package*/ JsResult(CallbackProxy proxy, boolean defaultVal) {
- mProxy = proxy;
- mDefaultValue = defaultVal;
- }
-
- /*package*/ final boolean getResult() {
- return mResult;
- }
-
- /*package*/ final void setReady() {
- mReady = true;
- if (mTriedToNotifyBeforeReady) {
- wakeUp();
- }
- }
-
- /*package*/ void handleDefault() {
- setReady();
- mResult = mDefaultValue;
- wakeUp();
- }
-
- /* Wake up the WebCore thread. */
- protected final void wakeUp() {
- if (mReady) {
- synchronized (mProxy) {
- mProxy.notify();
- }
- } else {
- mTriedToNotifyBeforeReady = true;
- }
- }
-}
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
deleted file mode 100644
index dfae17d..0000000
--- a/core/java/android/webkit/LoadListener.java
+++ /dev/null
@@ -1,1499 +0,0 @@
-/*
- * 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.content.Context;
-import android.net.WebAddress;
-import android.net.ParseException;
-import android.net.http.EventHandler;
-import android.net.http.Headers;
-import android.net.http.HttpAuthHeader;
-import android.net.http.RequestHandle;
-import android.net.http.SslCertificate;
-import android.net.http.SslError;
-import android.net.http.SslCertificate;
-
-import android.os.Handler;
-import android.os.Message;
-import android.util.Config;
-import android.util.Log;
-import android.webkit.CacheManager.CacheResult;
-
-import com.android.internal.R;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Vector;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-
-import org.apache.commons.codec.binary.Base64;
-
-class LoadListener extends Handler implements EventHandler {
-
- private static final String LOGTAG = "webkit";
-
- // Messages used internally to communicate state between the
- // Network thread and the WebCore thread.
- private static final int MSG_CONTENT_HEADERS = 100;
- private static final int MSG_CONTENT_DATA = 110;
- private static final int MSG_CONTENT_FINISHED = 120;
- private static final int MSG_CONTENT_ERROR = 130;
- private static final int MSG_LOCATION_CHANGED = 140;
- private static final int MSG_LOCATION_CHANGED_REQUEST = 150;
- private static final int MSG_STATUS = 160;
- private static final int MSG_SSL_CERTIFICATE = 170;
- private static final int MSG_SSL_ERROR = 180;
-
- // Standard HTTP status codes in a more representative format
- private static final int HTTP_OK = 200;
- private static final int HTTP_MOVED_PERMANENTLY = 301;
- private static final int HTTP_FOUND = 302;
- private static final int HTTP_SEE_OTHER = 303;
- private static final int HTTP_NOT_MODIFIED = 304;
- private static final int HTTP_TEMPORARY_REDIRECT = 307;
- private static final int HTTP_AUTH = 401;
- private static final int HTTP_NOT_FOUND = 404;
- private static final int HTTP_PROXY_AUTH = 407;
-
- private static int sNativeLoaderCount;
-
- private final ByteArrayBuilder mDataBuilder = new ByteArrayBuilder(8192);
-
- private String mUrl;
- private WebAddress mUri;
- private boolean mPermanent;
- private String mOriginalUrl;
- private Context mContext;
- private BrowserFrame mBrowserFrame;
- private int mNativeLoader;
- private String mMimeType;
- private String mEncoding;
- private String mTransferEncoding;
- private int mStatusCode;
- private String mStatusText;
- public long mContentLength; // Content length of the incoming data
- private boolean mCancelled; // The request has been cancelled.
- private boolean mAuthFailed; // indicates that the prev. auth failed
- private CacheLoader mCacheLoader;
- private CacheManager.CacheResult mCacheResult;
- private HttpAuthHeader mAuthHeader;
- private int mErrorID = OK;
- private String mErrorDescription;
- private SslError mSslError;
- private RequestHandle mRequestHandle;
-
- // Request data. It is only valid when we are doing a load from the
- // cache. It is needed if the cache returns a redirect
- private String mMethod;
- private Map<String, String> mRequestHeaders;
- private byte[] mPostData;
- private boolean mIsHighPriority;
- // Flag to indicate that this load is synchronous.
- private boolean mSynchronous;
- private Vector<Message> mMessageQueue;
-
- // Does this loader correspond to the main-frame top-level page?
- private boolean mIsMainPageLoader;
-
- private Headers mHeaders;
-
- // =========================================================================
- // Public functions
- // =========================================================================
-
- public static LoadListener getLoadListener(
- Context context, BrowserFrame frame, String url,
- int nativeLoader, boolean synchronous, boolean isMainPageLoader) {
-
- sNativeLoaderCount += 1;
- return new LoadListener(
- context, frame, url, nativeLoader, synchronous, isMainPageLoader);
- }
-
- public static int getNativeLoaderCount() {
- return sNativeLoaderCount;
- }
-
- LoadListener(Context context, BrowserFrame frame, String url,
- int nativeLoader, boolean synchronous, boolean isMainPageLoader) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener constructor url=" + url);
- }
- mContext = context;
- mBrowserFrame = frame;
- setUrl(url);
- mNativeLoader = nativeLoader;
- mMimeType = "";
- mEncoding = "";
- mSynchronous = synchronous;
- if (synchronous) {
- mMessageQueue = new Vector<Message>();
- }
- mIsMainPageLoader = isMainPageLoader;
- }
-
- /**
- * We keep a count of refs to the nativeLoader so we do not create
- * so many LoadListeners that the GREFs blow up
- */
- private void clearNativeLoader() {
- sNativeLoaderCount -= 1;
- mNativeLoader = 0;
- }
-
- /*
- * This message handler is to facilitate communication between the network
- * thread and the browser thread.
- */
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_CONTENT_HEADERS:
- /*
- * This message is sent when the LoadListener has headers
- * available. The headers are sent onto WebCore to see what we
- * should do with them.
- */
- handleHeaders((Headers) msg.obj);
- break;
-
- case MSG_CONTENT_DATA:
- /*
- * This message is sent when the LoadListener has data available
- * in it's data buffer. This data buffer could be filled from a
- * file (this thread) or from http (Network thread).
- */
- if (mNativeLoader != 0 && !ignoreCallbacks()) {
- commitLoad();
- }
- break;
-
- case MSG_CONTENT_FINISHED:
- /*
- * This message is sent when the LoadListener knows that the
- * load is finished. This message is not sent in the case of an
- * error.
- *
- */
- handleEndData();
- break;
-
- case MSG_CONTENT_ERROR:
- /*
- * This message is sent when a load error has occured. The
- * LoadListener will clean itself up.
- */
- handleError(msg.arg1, (String) msg.obj);
- break;
-
- case MSG_LOCATION_CHANGED:
- /*
- * This message is sent from LoadListener.endData to inform the
- * browser activity that the location of the top level page
- * changed.
- */
- doRedirect();
- break;
-
- case MSG_LOCATION_CHANGED_REQUEST:
- /*
- * This message is sent from endData on receipt of a 307
- * Temporary Redirect in response to a POST -- the user must
- * confirm whether to continue loading. If the user says Yes,
- * we simply call MSG_LOCATION_CHANGED. If the user says No,
- * we call MSG_CONTENT_FINISHED.
- */
- Message contMsg = obtainMessage(MSG_LOCATION_CHANGED);
- Message stopMsg = obtainMessage(MSG_CONTENT_FINISHED);
- mBrowserFrame.getCallbackProxy().onFormResubmission(
- stopMsg, contMsg);
- break;
-
- case MSG_STATUS:
- /*
- * This message is sent from the network thread when the http
- * stack has received the status response from the server.
- */
- HashMap status = (HashMap) msg.obj;
- handleStatus(((Integer) status.get("major")).intValue(),
- ((Integer) status.get("minor")).intValue(),
- ((Integer) status.get("code")).intValue(),
- (String) status.get("reason"));
- break;
-
- case MSG_SSL_CERTIFICATE:
- /*
- * This message is sent when the network thread receives a ssl
- * certificate.
- */
- handleCertificate((SslCertificate) msg.obj);
- break;
-
- case MSG_SSL_ERROR:
- /*
- * This message is sent when the network thread encounters a
- * ssl error.
- */
- handleSslError((SslError) msg.obj);
- break;
- }
- }
-
- /**
- * @return The loader's BrowserFrame.
- */
- BrowserFrame getFrame() {
- return mBrowserFrame;
- }
-
- Context getContext() {
- return mContext;
- }
-
- /* package */ boolean isSynchronous() {
- return mSynchronous;
- }
-
- /**
- * @return True iff the load has been cancelled
- */
- public boolean cancelled() {
- return mCancelled;
- }
-
- /**
- * Parse the headers sent from the server.
- * @param headers gives up the HeaderGroup
- * IMPORTANT: as this is called from network thread, can't call native
- * directly
- */
- public void headers(Headers headers) {
- if (Config.LOGV) Log.v(LOGTAG, "LoadListener.headers");
- sendMessageInternal(obtainMessage(MSG_CONTENT_HEADERS, headers));
- }
-
- // Does the header parsing work on the WebCore thread.
- private void handleHeaders(Headers headers) {
- if (mCancelled) return;
- mHeaders = headers;
- mMimeType = "";
- mEncoding = "";
-
- ArrayList<String> cookies = headers.getSetCookie();
- for (int i = 0; i < cookies.size(); ++i) {
- CookieManager.getInstance().setCookie(mUri, cookies.get(i));
- }
-
- long contentLength = headers.getContentLength();
- if (contentLength != Headers.NO_CONTENT_LENGTH) {
- mContentLength = contentLength;
- } else {
- mContentLength = 0;
- }
-
- String contentType = headers.getContentType();
- if (contentType != null) {
- parseContentTypeHeader(contentType);
-
- // If we have one of "generic" MIME types, try to deduce
- // the right MIME type from the file extension (if any):
- if (mMimeType.equalsIgnoreCase("text/plain") ||
- mMimeType.equalsIgnoreCase("application/octet-stream")) {
-
- String newMimeType = guessMimeTypeFromExtension();
- if (newMimeType != null) {
- mMimeType = newMimeType;
- }
- } else if (mMimeType.equalsIgnoreCase("text/vnd.wap.wml")) {
- // As we don't support wml, render it as plain text
- mMimeType = "text/plain";
- } else {
- // XXX: Until the servers send us either correct xhtml or
- // text/html, treat application/xhtml+xml as text/html.
- // It seems that xhtml+xml and vnd.wap.xhtml+xml mime
- // subtypes are used interchangeably. So treat them the same.
- if (mMimeType.equalsIgnoreCase("application/xhtml+xml") ||
- mMimeType.equals("application/vnd.wap.xhtml+xml")) {
- mMimeType = "text/html";
- }
- }
- } else {
- /* Often when servers respond with 304 Not Modified or a
- Redirect, then they don't specify a MIMEType. When this
- occurs, the function below is called. In the case of
- 304 Not Modified, the cached headers are used rather
- than the headers that are returned from the server. */
- guessMimeType();
- }
-
- // is it an authentication request?
- boolean mustAuthenticate = (mStatusCode == HTTP_AUTH ||
- mStatusCode == HTTP_PROXY_AUTH);
- // is it a proxy authentication request?
- boolean isProxyAuthRequest = (mStatusCode == HTTP_PROXY_AUTH);
- // is this authentication request due to a failed attempt to
- // authenticate ealier?
- mAuthFailed = false;
-
- // if we tried to authenticate ourselves last time
- if (mAuthHeader != null) {
- // we failed, if we must to authenticate again now and
- // we have a proxy-ness match
- mAuthFailed = (mustAuthenticate &&
- isProxyAuthRequest == mAuthHeader.isProxy());
-
- // if we did NOT fail and last authentication request was a
- // proxy-authentication request
- if (!mAuthFailed && mAuthHeader.isProxy()) {
- Network network = Network.getInstance(mContext);
- // if we have a valid proxy set
- if (network.isValidProxySet()) {
- /* The proxy credentials can be read in the WebCore thread
- */
- synchronized (network) {
- // save authentication credentials for pre-emptive proxy
- // authentication
- network.setProxyUsername(mAuthHeader.getUsername());
- network.setProxyPassword(mAuthHeader.getPassword());
- }
- }
- }
- }
- // it is only here that we can reset the last mAuthHeader object
- // (if existed) and start a new one!!!
- mAuthHeader = null;
- if (mustAuthenticate) {
- if (mStatusCode == HTTP_AUTH) {
- mAuthHeader = parseAuthHeader(
- headers.getWwwAuthenticate());
- } else {
- mAuthHeader = parseAuthHeader(
- headers.getProxyAuthenticate());
- // if successfully parsed the header
- if (mAuthHeader != null) {
- // mark the auth-header object as a proxy
- mAuthHeader.setProxy();
- }
- }
- }
-
- // Only create a cache file if the server has responded positively.
- if ((mStatusCode == HTTP_OK ||
- mStatusCode == HTTP_FOUND ||
- mStatusCode == HTTP_MOVED_PERMANENTLY ||
- mStatusCode == HTTP_TEMPORARY_REDIRECT) &&
- mNativeLoader != 0) {
- // Content arriving from a StreamLoader (eg File, Cache or Data)
- // will not be cached as they have the header:
- // cache-control: no-store
- mCacheResult = CacheManager.createCacheFile(mUrl, mStatusCode,
- headers, mMimeType, false);
- if (mCacheResult != null) {
- mCacheResult.encoding = mEncoding;
- }
- }
- commitHeadersCheckRedirect();
- }
-
- /**
- * @return True iff this loader is in the proxy-authenticate state.
- */
- boolean proxyAuthenticate() {
- if (mAuthHeader != null) {
- return mAuthHeader.isProxy();
- }
-
- return false;
- }
-
- /**
- * Report the status of the response.
- * TODO: Comments about each parameter.
- * IMPORTANT: as this is called from network thread, can't call native
- * directly
- */
- public void status(int majorVersion, int minorVersion,
- int code, /* Status-Code value */ String reasonPhrase) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener: from: " + mUrl
- + " major: " + majorVersion
- + " minor: " + minorVersion
- + " code: " + code
- + " reason: " + reasonPhrase);
- }
- HashMap status = new HashMap();
- status.put("major", majorVersion);
- status.put("minor", minorVersion);
- status.put("code", code);
- status.put("reason", reasonPhrase);
- sendMessageInternal(obtainMessage(MSG_STATUS, status));
- }
-
- // Handle the status callback on the WebCore thread.
- private void handleStatus(int major, int minor, int code, String reason) {
- if (mCancelled) return;
-
- mStatusCode = code;
- mStatusText = reason;
- mPermanent = false;
- }
-
- /**
- * Implementation of certificate handler for EventHandler.
- * Called every time a resource is loaded via a secure
- * connection. In this context, can be called multiple
- * times if we have redirects
- * @param certificate The SSL certifcate
- * IMPORTANT: as this is called from network thread, can't call native
- * directly
- */
- public void certificate(SslCertificate certificate) {
- sendMessageInternal(obtainMessage(MSG_SSL_CERTIFICATE, certificate));
- }
-
- // Handle the certificate on the WebCore thread.
- private void handleCertificate(SslCertificate certificate) {
- // if this is the top-most main-frame page loader
- if (mIsMainPageLoader) {
- // update the browser frame (ie, the main frame)
- mBrowserFrame.certificate(certificate);
- }
- }
-
- /**
- * Implementation of error handler for EventHandler.
- * Subclasses should call this method to have error fields set.
- * @param id The error id described by EventHandler.
- * @param description A string description of the error.
- * IMPORTANT: as this is called from network thread, can't call native
- * directly
- */
- public void error(int id, String description) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener.error url:" +
- url() + " id:" + id + " description:" + description);
- }
- sendMessageInternal(obtainMessage(MSG_CONTENT_ERROR, id, 0, description));
- }
-
- // Handle the error on the WebCore thread.
- private void handleError(int id, String description) {
- mErrorID = id;
- mErrorDescription = description;
- detachRequestHandle();
- notifyError();
- tearDown();
- }
-
- /**
- * Add data to the internal collection of data. This function is used by
- * the data: scheme, about: scheme and http/https schemes.
- * @param data A byte array containing the content.
- * @param length The length of data.
- * IMPORTANT: as this is called from network thread, can't call native
- * directly
- * XXX: Unlike the other network thread methods, this method can do the
- * work of decoding the data and appending it to the data builder because
- * mDataBuilder is a thread-safe structure.
- */
- public void data(byte[] data, int length) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener.data(): url: " + url());
- }
-
- // Decode base64 data
- // Note: It's fine that we only decode base64 here and not in the other
- // data call because the only caller of the stream version is not
- // base64 encoded.
- if ("base64".equalsIgnoreCase(mTransferEncoding)) {
- if (length < data.length) {
- byte[] trimmedData = new byte[length];
- System.arraycopy(data, 0, trimmedData, 0, length);
- data = trimmedData;
- }
- data = Base64.decodeBase64(data);
- length = data.length;
- }
- // Synchronize on mData because commitLoad may write mData to WebCore
- // and we don't want to replace mData or mDataLength at the same time
- // as a write.
- boolean sendMessage = false;
- synchronized (mDataBuilder) {
- sendMessage = mDataBuilder.isEmpty();
- mDataBuilder.append(data, 0, length);
- }
- if (sendMessage) {
- // Send a message whenever data comes in after a write to WebCore
- sendMessageInternal(obtainMessage(MSG_CONTENT_DATA));
- }
- }
-
- /**
- * Event handler's endData call. Send a message to the handler notifying
- * them that the data has finished.
- * IMPORTANT: as this is called from network thread, can't call native
- * directly
- */
- public void endData() {
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener.endData(): url: " + url());
- }
- sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED));
- }
-
- // Handle the end of data.
- private void handleEndData() {
- if (mCancelled) return;
-
- switch (mStatusCode) {
- case HTTP_MOVED_PERMANENTLY:
- // 301 - permanent redirect
- mPermanent = true;
- case HTTP_FOUND:
- case HTTP_SEE_OTHER:
- case HTTP_TEMPORARY_REDIRECT:
- // 301, 302, 303, and 307 - redirect
- if (mStatusCode == HTTP_TEMPORARY_REDIRECT) {
- if (mRequestHandle != null &&
- mRequestHandle.getMethod().equals("POST")) {
- sendMessageInternal(obtainMessage(
- MSG_LOCATION_CHANGED_REQUEST));
- } else if (mMethod != null && mMethod.equals("POST")) {
- sendMessageInternal(obtainMessage(
- MSG_LOCATION_CHANGED_REQUEST));
- } else {
- sendMessageInternal(obtainMessage(MSG_LOCATION_CHANGED));
- }
- } else {
- sendMessageInternal(obtainMessage(MSG_LOCATION_CHANGED));
- }
- return;
-
- case HTTP_AUTH:
- case HTTP_PROXY_AUTH:
- // According to rfc2616, the response for HTTP_AUTH must include
- // WWW-Authenticate header field and the response for
- // HTTP_PROXY_AUTH must include Proxy-Authenticate header field.
- if (mAuthHeader != null &&
- (Network.getInstance(mContext).isValidProxySet() ||
- !mAuthHeader.isProxy())) {
- Network.getInstance(mContext).handleAuthRequest(this);
- return;
- }
- break; // use default
-
- case HTTP_NOT_MODIFIED:
- // Server could send back NOT_MODIFIED even if we didn't
- // ask for it, so make sure we have a valid CacheLoader
- // before calling it.
- if (mCacheLoader != null) {
- detachRequestHandle();
- mCacheLoader.load();
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener cache load url=" + url());
- }
- return;
- }
- break; // use default
-
- case HTTP_NOT_FOUND:
- // Not an error, the server can send back content.
- default:
- break;
- }
- detachRequestHandle();
- tearDown();
- }
-
- /* This method is called from CacheLoader when the initial request is
- * serviced by the Cache. */
- /* package */ void setCacheLoader(CacheLoader c) {
- mCacheLoader = c;
- }
-
- /**
- * Check the cache for the current URL, and load it if it is valid.
- *
- * @param headers for the request
- * @return true if cached response is used.
- */
- boolean checkCache(Map<String, String> headers) {
- // Get the cache file name for the current URL
- CacheResult result = CacheManager.getCacheFile(url(),
- headers);
-
- // Go ahead and set the cache loader to null in case the result is
- // null.
- mCacheLoader = null;
-
- if (result != null) {
- // The contents of the cache may need to be revalidated so just
- // remember the cache loader in the case that the server responds
- // positively to the cached content. This is also used to detect if
- // a redirect came from the cache.
- mCacheLoader = new CacheLoader(this, result);
-
- // If I got a cachedUrl and the revalidation header was not
- // added, then the cached content valid, we should use it.
- if (!headers.containsKey(
- CacheManager.HEADER_KEY_IFNONEMATCH) &&
- !headers.containsKey(
- CacheManager.HEADER_KEY_IFMODIFIEDSINCE)) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "FrameLoader: HTTP URL in cache " +
- "and usable: " + url());
- }
- // Load the cached file
- mCacheLoader.load();
- return true;
- }
- }
- return false;
- }
-
- /**
- * SSL certificate error callback. Handles SSL error(s) on the way up
- * to the user.
- * IMPORTANT: as this is called from network thread, can't call native
- * directly
- */
- public void handleSslErrorRequest(SslError error) {
- if (Config.LOGV) {
- Log.v(LOGTAG,
- "LoadListener.handleSslErrorRequest(): url:" + url() +
- " primary error: " + error.getPrimaryError() +
- " certificate: " + error.getCertificate());
- }
- sendMessageInternal(obtainMessage(MSG_SSL_ERROR, error));
- }
-
- // Handle the ssl error on the WebCore thread.
- private void handleSslError(SslError error) {
- if (!mCancelled) {
- mSslError = error;
- Network.getInstance(mContext).handleSslErrorRequest(this);
- }
- }
-
- /**
- * @return HTTP authentication realm or null if none.
- */
- String realm() {
- if (mAuthHeader == null) {
- return null;
- } else {
- return mAuthHeader.getRealm();
- }
- }
-
- /**
- * Returns true iff an HTTP authentication problem has
- * occured (credentials invalid).
- */
- boolean authCredentialsInvalid() {
- // if it is digest and the nonce is stale, we just
- // resubmit with a new nonce
- return (mAuthFailed &&
- !(mAuthHeader.isDigest() && mAuthHeader.getStale()));
- }
-
- /**
- * @return The last SSL error or null if there is none
- */
- SslError sslError() {
- return mSslError;
- }
-
- /**
- * Handles SSL error(s) on the way down from the user
- * (the user has already provided their feedback).
- */
- void handleSslErrorResponse(boolean proceed) {
- if (mRequestHandle != null) {
- mRequestHandle.handleSslErrorResponse(proceed);
- }
- }
-
- /**
- * Uses user-supplied credentials to restar a request.
- */
- void handleAuthResponse(String username, String password) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener.handleAuthResponse: url: " + mUrl
- + " username: " + username
- + " password: " + password);
- }
-
- // create and queue an authentication-response
- if (username != null && password != null) {
- if (mAuthHeader != null && mRequestHandle != null) {
- mAuthHeader.setUsername(username);
- mAuthHeader.setPassword(password);
-
- int scheme = mAuthHeader.getScheme();
- if (scheme == HttpAuthHeader.BASIC) {
- // create a basic response
- boolean isProxy = mAuthHeader.isProxy();
-
- mRequestHandle.setupBasicAuthResponse(isProxy,
- username, password);
- } else {
- if (scheme == HttpAuthHeader.DIGEST) {
- // create a digest response
- boolean isProxy = mAuthHeader.isProxy();
-
- String realm = mAuthHeader.getRealm();
- String nonce = mAuthHeader.getNonce();
- String qop = mAuthHeader.getQop();
- String algorithm = mAuthHeader.getAlgorithm();
- String opaque = mAuthHeader.getOpaque();
-
- mRequestHandle.setupDigestAuthResponse
- (isProxy, username, password, realm,
- nonce, qop, algorithm, opaque);
- }
- }
- }
- }
- }
-
- /**
- * This is called when a request can be satisfied by the cache, however,
- * the cache result could be a redirect. In this case we need to issue
- * the network request.
- * @param method
- * @param headers
- * @param postData
- * @param isHighPriority
- */
- void setRequestData(String method, Map<String, String> headers,
- byte[] postData, boolean isHighPriority) {
- mMethod = method;
- mRequestHeaders = headers;
- mPostData = postData;
- mIsHighPriority = isHighPriority;
- }
-
- /**
- * @return The current URL associated with this load.
- */
- String url() {
- return mUrl;
- }
-
- /**
- * @return The current WebAddress associated with this load.
- */
- WebAddress getWebAddress() {
- return mUri;
- }
-
- /**
- * @return URL hostname (current URL).
- */
- String host() {
- if (mUri != null) {
- return mUri.mHost;
- }
-
- return null;
- }
-
- /**
- * @return The original URL associated with this load.
- */
- String originalUrl() {
- if (mOriginalUrl != null) {
- return mOriginalUrl;
- } else {
- return mUrl;
- }
- }
-
- void attachRequestHandle(RequestHandle requestHandle) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener.attachRequestHandle(): " +
- "requestHandle: " + requestHandle);
- }
- mRequestHandle = requestHandle;
- }
-
- void detachRequestHandle() {
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener.detachRequestHandle(): " +
- "requestHandle: " + mRequestHandle);
- }
- mRequestHandle = null;
- }
-
- /*
- * This function is called from native WebCore code to
- * notify this LoadListener that the content it is currently
- * downloading should be saved to a file and not sent to
- * WebCore.
- */
- void downloadFile() {
- // Setting the Cache Result to null ensures that this
- // content is not added to the cache
- mCacheResult = null;
-
- // Inform the client that they should download a file
- mBrowserFrame.getCallbackProxy().onDownloadStart(url(),
- mBrowserFrame.getUserAgentString(),
- mHeaders.getContentDisposition(),
- mMimeType, mContentLength);
-
- // Cancel the download. We need to stop the http load.
- // The native loader object will get cleared by the call to
- // cancel() but will also be cleared on the WebCore side
- // when this function returns.
- cancel();
- }
-
- /*
- * This function is called from native WebCore code to
- * find out if the given URL is in the cache, and if it can
- * be used. This is just for forward/back navigation to a POST
- * URL.
- */
- static boolean willLoadFromCache(String url) {
- boolean inCache = CacheManager.getCacheFile(url, null) != null;
- if (Config.LOGV) {
- Log.v(LOGTAG, "willLoadFromCache: " + url + " in cache: " +
- inCache);
- }
- return inCache;
- }
-
- /*
- * Reset the cancel flag. This is used when we are resuming a stopped
- * download. To suspend a download, we cancel it. It can also be cancelled
- * when it has run out of disk space. In this situation, the download
- * can be resumed.
- */
- void resetCancel() {
- mCancelled = false;
- }
-
- String mimeType() {
- return mMimeType;
- }
-
- /*
- * Return the size of the content being downloaded. This represents the
- * full content size, even under the situation where the download has been
- * resumed after interruption.
- *
- * @ return full content size
- */
- long contentLength() {
- return mContentLength;
- }
-
- // Commit the headers if the status code is not a redirect.
- private void commitHeadersCheckRedirect() {
- if (mCancelled) return;
-
- // do not call webcore if it is redirect. According to the code in
- // InspectorController::willSendRequest(), the response is only updated
- // when it is not redirect.
- if ((mStatusCode >= 301 && mStatusCode <= 303) || mStatusCode == 307) {
- return;
- }
-
- commitHeaders();
- }
-
- // This commits the headers without checking the response status code.
- private void commitHeaders() {
- // Commit the headers to WebCore
- int nativeResponse = createNativeResponse();
- // The native code deletes the native response object.
- nativeReceivedResponse(nativeResponse);
- }
-
- /**
- * Create a WebCore response object so that it can be used by
- * nativeReceivedResponse or nativeRedirectedToUrl
- * @return native response pointer
- */
- private int createNativeResponse() {
- // The reason we change HTTP_NOT_MODIFIED to HTTP_OK is because we know
- // that WebCore never sends the if-modified-since header. Our
- // CacheManager does it for us. If the server responds with a 304, then
- // we treat it like it was a 200 code and proceed with loading the file
- // from the cache.
- int statusCode = mStatusCode == HTTP_NOT_MODIFIED
- ? HTTP_OK : mStatusCode;
- // pass content-type content-length and content-encoding
- final int nativeResponse = nativeCreateResponse(
- mUrl, statusCode, mStatusText,
- mMimeType, mContentLength, mEncoding,
- mCacheResult == null ? 0 : mCacheResult.expires / 1000);
- if (mHeaders != null) {
- mHeaders.getHeaders(new Headers.HeaderCallback() {
- public void header(String name, String value) {
- nativeSetResponseHeader(nativeResponse, name, value);
- }
- });
- }
- return nativeResponse;
- }
-
- /**
- * Commit the load. It should be ok to call repeatedly but only before
- * tearDown is called.
- */
- private void commitLoad() {
- if (mCancelled) return;
-
- // Give the data to WebKit now
- PerfChecker checker = new PerfChecker();
- ByteArrayBuilder.Chunk c;
- while (true) {
- c = mDataBuilder.getFirstChunk();
- if (c == null) break;
-
- if (c.mLength != 0) {
- if (mCacheResult != null) {
- try {
- mCacheResult.outStream.write(c.mArray, 0, c.mLength);
- } catch (IOException e) {
- mCacheResult = null;
- }
- }
- nativeAddData(c.mArray, c.mLength);
- }
- mDataBuilder.releaseChunk(c);
- checker.responseAlert("res nativeAddData");
- }
- }
-
- /**
- * Tear down the load. Subclasses should clean up any mess because of
- * cancellation or errors during the load.
- */
- void tearDown() {
- if (mCacheResult != null) {
- if (getErrorID() == OK) {
- CacheManager.saveCacheFile(mUrl, mCacheResult);
- }
-
- // we need to reset mCacheResult to be null
- // resource loader's tearDown will call into WebCore's
- // nativeFinish, which in turn calls loader.cancel().
- // If we don't reset mCacheFile, the file will be deleted.
- mCacheResult = null;
- }
- if (mNativeLoader != 0) {
- PerfChecker checker = new PerfChecker();
- nativeFinished();
- checker.responseAlert("res nativeFinished");
- clearNativeLoader();
- }
- }
-
- /**
- * Helper for getting the error ID.
- * @return errorID.
- */
- private int getErrorID() {
- return mErrorID;
- }
-
- /**
- * Return the error description.
- * @return errorDescription.
- */
- private String getErrorDescription() {
- return mErrorDescription;
- }
-
- /**
- * Notify the loader we encountered an error.
- */
- void notifyError() {
- if (mNativeLoader != 0) {
- String description = getErrorDescription();
- if (description == null) description = "";
- nativeError(getErrorID(), description, url());
- clearNativeLoader();
- }
- }
-
- /**
- * Cancel a request.
- * FIXME: This will only work if the request has yet to be handled. This
- * is in no way guarenteed if requests are served in a separate thread.
- * It also causes major problems if cancel is called during an
- * EventHandler's method call.
- */
- public void cancel() {
- if (Config.LOGV) {
- if (mRequestHandle == null) {
- Log.v(LOGTAG, "LoadListener.cancel(): no requestHandle");
- } else {
- Log.v(LOGTAG, "LoadListener.cancel()");
- }
- }
- if (mRequestHandle != null) {
- mRequestHandle.cancel();
- mRequestHandle = null;
- }
-
- mCacheResult = null;
- mCancelled = true;
-
- clearNativeLoader();
- }
-
- // This count is transferred from RequestHandle to LoadListener when
- // loading from the cache so that we can detect redirect loops that switch
- // between the network and the cache.
- private int mCacheRedirectCount;
-
- /*
- * Perform the actual redirection. This involves setting up the new URL,
- * informing WebCore and then telling the Network to start loading again.
- */
- private void doRedirect() {
- // as cancel() can cancel the load before doRedirect() is
- // called through handleMessage, needs to check to see if we
- // are canceled before proceed
- if (mCancelled) {
- return;
- }
-
- // Do the same check for a redirect loop that
- // RequestHandle.setupRedirect does.
- if (mCacheRedirectCount >= RequestHandle.MAX_REDIRECT_COUNT) {
- handleError(EventHandler.ERROR_REDIRECT_LOOP, mContext.getString(
- R.string.httpErrorRedirectLoop));
- return;
- }
-
- String redirectTo = mHeaders.getLocation();
- if (redirectTo != null) {
- int nativeResponse = createNativeResponse();
- redirectTo =
- nativeRedirectedToUrl(mUrl, redirectTo, nativeResponse);
- // nativeRedirectedToUrl() may call cancel(), e.g. when redirect
- // from a https site to a http site, check mCancelled again
- if (mCancelled) {
- return;
- }
- if (redirectTo == null) {
- Log.d(LOGTAG, "Redirection failed for "
- + mHeaders.getLocation());
- cancel();
- return;
- } else if (!URLUtil.isNetworkUrl(redirectTo)) {
- final String text = mContext
- .getString(R.string.open_permission_deny)
- + "\n" + redirectTo;
- nativeAddData(text.getBytes(), text.length());
- nativeFinished();
- clearNativeLoader();
- return;
- }
-
- if (mOriginalUrl == null) {
- mOriginalUrl = mUrl;
- }
-
- // Cache the redirect response
- if (mCacheResult != null) {
- if (getErrorID() == OK) {
- CacheManager.saveCacheFile(mUrl, mCacheResult);
- }
- mCacheResult = null;
- }
-
- setUrl(redirectTo);
-
- // Redirect may be in the cache
- if (mRequestHeaders == null) {
- mRequestHeaders = new HashMap<String, String>();
- }
- boolean fromCache = false;
- if (mCacheLoader != null) {
- // This is a redirect from the cache loader. Increment the
- // redirect count to avoid redirect loops.
- mCacheRedirectCount++;
- fromCache = true;
- }
- if (!checkCache(mRequestHeaders)) {
- // mRequestHandle can be null when the request was satisfied
- // by the cache, and the cache returned a redirect
- if (mRequestHandle != null) {
- mRequestHandle.setupRedirect(redirectTo, mStatusCode,
- mRequestHeaders);
- } else {
- // If the original request came from the cache, there is no
- // RequestHandle, we have to create a new one through
- // Network.requestURL.
- Network network = Network.getInstance(getContext());
- if (!network.requestURL(mMethod, mRequestHeaders,
- mPostData, this, mIsHighPriority)) {
- // Signal a bad url error if we could not load the
- // redirection.
- handleError(EventHandler.ERROR_BAD_URL,
- mContext.getString(R.string.httpErrorBadUrl));
- return;
- }
- }
- if (fromCache) {
- // If we are coming from a cache load, we need to transfer
- // the redirect count to the new (or old) RequestHandle to
- // keep the redirect count in sync.
- mRequestHandle.setRedirectCount(mCacheRedirectCount);
- }
- } else if (!fromCache) {
- // Switching from network to cache means we need to grab the
- // redirect count from the RequestHandle to keep the count in
- // sync. Add 1 to account for the current redirect.
- mCacheRedirectCount = mRequestHandle.getRedirectCount() + 1;
- }
- // Clear the buffered data since the redirect is valid.
- mDataBuilder.clear();
- } else {
- commitHeaders();
- commitLoad();
- tearDown();
- }
-
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener.onRedirect(): redirect to: " +
- redirectTo);
- }
- }
-
- /**
- * Parses the content-type header.
- */
- private static final Pattern CONTENT_TYPE_PATTERN =
- Pattern.compile("^([a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$");
-
- private void parseContentTypeHeader(String contentType) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "LoadListener.parseContentTypeHeader: " +
- "contentType: " + contentType);
- }
-
- if (contentType != null) {
- int i = contentType.indexOf(';');
- if (i >= 0) {
- mMimeType = contentType.substring(0, i);
-
- int j = contentType.indexOf('=', i);
- if (j > 0) {
- i = contentType.indexOf(';', j);
- if (i < j) {
- i = contentType.length();
- }
- mEncoding = contentType.substring(j + 1, i);
- } else {
- mEncoding = contentType.substring(i + 1);
- }
- // Trim excess whitespace.
- mEncoding = mEncoding.trim();
-
- if (i < contentType.length() - 1) {
- // for data: uri the mimeType and encoding have
- // the form image/jpeg;base64 or text/plain;charset=utf-8
- // or text/html;charset=utf-8;base64
- mTransferEncoding = contentType.substring(i + 1).trim();
- }
- } else {
- mMimeType = contentType;
- }
-
- // Trim leading and trailing whitespace
- mMimeType = mMimeType.trim();
-
- try {
- Matcher m = CONTENT_TYPE_PATTERN.matcher(mMimeType);
- if (m.find()) {
- mMimeType = m.group(1);
- } else {
- guessMimeType();
- }
- } catch (IllegalStateException ex) {
- guessMimeType();
- }
- }
- }
-
- /**
- * @return The HTTP-authentication object or null if there
- * is no supported scheme in the header.
- * If there are several valid schemes present, we pick the
- * strongest one. If there are several schemes of the same
- * strength, we pick the one that comes first.
- */
- private HttpAuthHeader parseAuthHeader(String header) {
- if (header != null) {
- int posMax = 256;
- int posLen = 0;
- int[] pos = new int [posMax];
-
- int headerLen = header.length();
- if (headerLen > 0) {
- // first, we find all unquoted instances of 'Basic' and 'Digest'
- boolean quoted = false;
- for (int i = 0; i < headerLen && posLen < posMax; ++i) {
- if (header.charAt(i) == '\"') {
- quoted = !quoted;
- } else {
- if (!quoted) {
- if (header.regionMatches(true, i,
- HttpAuthHeader.BASIC_TOKEN, 0,
- HttpAuthHeader.BASIC_TOKEN.length())) {
- pos[posLen++] = i;
- continue;
- }
-
- if (header.regionMatches(true, i,
- HttpAuthHeader.DIGEST_TOKEN, 0,
- HttpAuthHeader.DIGEST_TOKEN.length())) {
- pos[posLen++] = i;
- continue;
- }
- }
- }
- }
- }
-
- if (posLen > 0) {
- // consider all digest schemes first (if any)
- for (int i = 0; i < posLen; i++) {
- if (header.regionMatches(true, pos[i],
- HttpAuthHeader.DIGEST_TOKEN, 0,
- HttpAuthHeader.DIGEST_TOKEN.length())) {
- String sub = header.substring(pos[i],
- (i + 1 < posLen ? pos[i + 1] : headerLen));
-
- HttpAuthHeader rval = new HttpAuthHeader(sub);
- if (rval.isSupportedScheme()) {
- // take the first match
- return rval;
- }
- }
- }
-
- // ...then consider all basic schemes (if any)
- for (int i = 0; i < posLen; i++) {
- if (header.regionMatches(true, pos[i],
- HttpAuthHeader.BASIC_TOKEN, 0,
- HttpAuthHeader.BASIC_TOKEN.length())) {
- String sub = header.substring(pos[i],
- (i + 1 < posLen ? pos[i + 1] : headerLen));
-
- HttpAuthHeader rval = new HttpAuthHeader(sub);
- if (rval.isSupportedScheme()) {
- // take the first match
- return rval;
- }
- }
- }
- }
- }
-
- return null;
- }
-
- /**
- * If the content is a redirect or not modified we should not send
- * any data into WebCore as that will cause it create a document with
- * the data, then when we try to provide the real content, it will assert.
- *
- * @return True iff the callback should be ignored.
- */
- private boolean ignoreCallbacks() {
- return (mCancelled || mAuthHeader != null ||
- (mStatusCode > 300 && mStatusCode < 400));
- }
-
- /**
- * Sets the current URL associated with this load.
- */
- void setUrl(String url) {
- if (url != null) {
- if (URLUtil.isDataUrl(url)) {
- // Don't strip anchor as that is a valid part of the URL
- mUrl = url;
- } else {
- mUrl = URLUtil.stripAnchor(url);
- }
- mUri = null;
- if (URLUtil.isNetworkUrl(mUrl)) {
- try {
- mUri = new WebAddress(mUrl);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- /**
- * Guesses MIME type if one was not specified. Defaults to 'text/html'. In
- * addition, tries to guess the MIME type based on the extension.
- *
- */
- private void guessMimeType() {
- // Data urls must have a valid mime type or a blank string for the mime
- // type (implying text/plain).
- if (URLUtil.isDataUrl(mUrl) && mMimeType.length() != 0) {
- cancel();
- final String text = mContext.getString(R.string.httpErrorBadUrl);
- handleError(EventHandler.ERROR_BAD_URL, text);
- } else {
- // Note: This is ok because this is used only for the main content
- // of frames. If no content-type was specified, it is fine to
- // default to text/html.
- mMimeType = "text/html";
- String newMimeType = guessMimeTypeFromExtension();
- if (newMimeType != null) {
- mMimeType = newMimeType;
- }
- }
- }
-
- /**
- * guess MIME type based on the file extension.
- */
- private String guessMimeTypeFromExtension() {
- // PENDING: need to normalize url
- if (Config.LOGV) {
- Log.v(LOGTAG, "guessMimeTypeFromExtension: mURL = " + mUrl);
- }
-
- String mimeType =
- MimeTypeMap.getSingleton().getMimeTypeFromExtension(
- MimeTypeMap.getFileExtensionFromUrl(mUrl));
-
- if (mimeType != null) {
- // XXX: Until the servers send us either correct xhtml or
- // text/html, treat application/xhtml+xml as text/html.
- if (mimeType.equals("application/xhtml+xml")) {
- mimeType = "text/html";
- }
- }
-
- return mimeType;
- }
-
- /**
- * Either send a message to ourselves or queue the message if this is a
- * synchronous load.
- */
- private void sendMessageInternal(Message msg) {
- if (mSynchronous) {
- mMessageQueue.add(msg);
- } else {
- sendMessage(msg);
- }
- }
-
- /**
- * Cycle through our messages for synchronous loads.
- */
- /* package */ void loadSynchronousMessages() {
- if (Config.DEBUG && !mSynchronous) {
- throw new AssertionError();
- }
- // Note: this can be called twice if it is a synchronous network load,
- // and there is a cache, but it needs to go to network to validate. If
- // validation succeed, the CacheLoader is used so this is first called
- // from http thread. Then it is called again from WebViewCore thread
- // after the load is completed. So make sure the queue is cleared but
- // don't set it to null.
- for (int size = mMessageQueue.size(); size > 0; size--) {
- handleMessage(mMessageQueue.remove(0));
- }
- }
-
- //=========================================================================
- // native functions
- //=========================================================================
-
- /**
- * Create a new native response object.
- * @param url The url of the resource.
- * @param statusCode The HTTP status code.
- * @param statusText The HTTP status text.
- * @param mimeType HTTP content-type.
- * @param expectedLength An estimate of the content length or the length
- * given by the server.
- * @param encoding HTTP encoding.
- * @param expireTime HTTP expires converted to seconds since the epoch.
- * @return The native response pointer.
- */
- private native int nativeCreateResponse(String url, int statusCode,
- String statusText, String mimeType, long expectedLength,
- String encoding, long expireTime);
-
- /**
- * Add a response header to the native object.
- * @param nativeResponse The native pointer.
- * @param key String key.
- * @param val String value.
- */
- private native void nativeSetResponseHeader(int nativeResponse, String key,
- String val);
-
- /**
- * Dispatch the response.
- * @param nativeResponse The native pointer.
- */
- private native void nativeReceivedResponse(int nativeResponse);
-
- /**
- * Add data to the loader.
- * @param data Byte array of data.
- * @param length Number of objects in data.
- */
- private native void nativeAddData(byte[] data, int length);
-
- /**
- * Tell the loader it has finished.
- */
- private native void nativeFinished();
-
- /**
- * tell the loader to redirect
- * @param baseUrl The base url.
- * @param redirectTo The url to redirect to.
- * @param nativeResponse The native pointer.
- * @return The new url that the resource redirected to.
- */
- private native String nativeRedirectedToUrl(String baseUrl,
- String redirectTo, int nativeResponse);
-
- /**
- * Tell the loader there is error
- * @param id
- * @param desc
- * @param failingUrl The url that failed.
- */
- private native void nativeError(int id, String desc, String failingUrl);
-
-}
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
deleted file mode 100644
index c9cc208..0000000
--- a/core/java/android/webkit/MimeTypeMap.java
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Copyright (C) 2007 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 java.util.HashMap;
-import java.util.regex.Pattern;
-
-/**
- * Two-way map that maps MIME-types to file extensions and vice versa.
- */
-public /* package */ class MimeTypeMap {
-
- /**
- * Singleton MIME-type map instance:
- */
- private static MimeTypeMap sMimeTypeMap;
-
- /**
- * MIME-type to file extension mapping:
- */
- private HashMap<String, String> mMimeTypeToExtensionMap;
-
- /**
- * File extension to MIME type mapping:
- */
- private HashMap<String, String> mExtensionToMimeTypeMap;
-
-
- /**
- * Creates a new MIME-type map.
- */
- private MimeTypeMap() {
- mMimeTypeToExtensionMap = new HashMap<String, String>();
- mExtensionToMimeTypeMap = new HashMap<String, String>();
- }
-
- /**
- * Returns the file extension or an empty string iff there is no
- * extension.
- */
- public static String getFileExtensionFromUrl(String url) {
- if (url != null && url.length() > 0) {
- int query = url.lastIndexOf('?');
- if (query > 0) {
- url = url.substring(0, query);
- }
- int filenamePos = url.lastIndexOf('/');
- String filename =
- 0 <= filenamePos ? url.substring(filenamePos + 1) : url;
-
- // if the filename contains special characters, we don't
- // consider it valid for our matching purposes:
- if (filename.length() > 0 &&
- Pattern.matches("[a-zA-Z_0-9\\.\\-\\(\\)]+", filename)) {
- int dotPos = filename.lastIndexOf('.');
- if (0 <= dotPos) {
- return filename.substring(dotPos + 1);
- }
- }
- }
-
- return "";
- }
-
- /**
- * Load an entry into the map. This does not check if the item already
- * exists, it trusts the caller!
- */
- private void loadEntry(String mimeType, String extension,
- boolean textType) {
- //
- // if we have an existing x --> y mapping, we do not want to
- // override it with another mapping x --> ?
- // this is mostly because of the way the mime-type map below
- // is constructed (if a mime type maps to several extensions
- // the first extension is considered the most popular and is
- // added first; we do not want to overwrite it later).
- //
- if (!mMimeTypeToExtensionMap.containsKey(mimeType)) {
- mMimeTypeToExtensionMap.put(mimeType, extension);
- }
-
- //
- // here, we don't want to map extensions to text MIME types;
- // otherwise, we will start replacing generic text/plain and
- // text/html with text MIME types that our platform does not
- // understand.
- //
- if (!textType) {
- mExtensionToMimeTypeMap.put(extension, mimeType);
- }
- }
-
- /**
- * @return True iff there is a mimeType entry in the map.
- */
- public boolean hasMimeType(String mimeType) {
- if (mimeType != null && mimeType.length() > 0) {
- return mMimeTypeToExtensionMap.containsKey(mimeType);
- }
-
- return false;
- }
-
- /**
- * @return The extension for the MIME type or null iff there is none.
- */
- public String getMimeTypeFromExtension(String extension) {
- if (extension != null && extension.length() > 0) {
- return mExtensionToMimeTypeMap.get(extension);
- }
-
- return null;
- }
-
- /**
- * @return True iff there is an extension entry in the map.
- */
- public boolean hasExtension(String extension) {
- if (extension != null && extension.length() > 0) {
- return mExtensionToMimeTypeMap.containsKey(extension);
- }
-
- return false;
- }
-
- /**
- * @return The MIME type for the extension or null iff there is none.
- */
- public String getExtensionFromMimeType(String mimeType) {
- if (mimeType != null && mimeType.length() > 0) {
- return mMimeTypeToExtensionMap.get(mimeType);
- }
-
- return null;
- }
-
- /**
- * @return The singleton instance of the MIME-type map.
- */
- public static MimeTypeMap getSingleton() {
- if (sMimeTypeMap == null) {
- sMimeTypeMap = new MimeTypeMap();
-
- // The following table is based on /etc/mime.types data minus
- // chemical/* MIME types and MIME types that don't map to any
- // file extensions. We also exclude top-level domain names to
- // deal with cases like:
- //
- // mail.google.com/a/google.com
- //
- // and "active" MIME types (due to potential security issues).
- //
- // Also, notice that not all data from this table is actually
- // added (see loadEntry method for more details).
-
- sMimeTypeMap.loadEntry("application/andrew-inset", "ez", false);
- sMimeTypeMap.loadEntry("application/dsptype", "tsp", false);
- sMimeTypeMap.loadEntry("application/futuresplash", "spl", false);
- sMimeTypeMap.loadEntry("application/hta", "hta", false);
- sMimeTypeMap.loadEntry("application/mac-binhex40", "hqx", false);
- sMimeTypeMap.loadEntry("application/mac-compactpro", "cpt", false);
- sMimeTypeMap.loadEntry("application/mathematica", "nb", false);
- sMimeTypeMap.loadEntry("application/msaccess", "mdb", false);
- sMimeTypeMap.loadEntry("application/oda", "oda", false);
- sMimeTypeMap.loadEntry("application/ogg", "ogg", false);
- sMimeTypeMap.loadEntry("application/pdf", "pdf", false);
- sMimeTypeMap.loadEntry("application/pgp-keys", "key", false);
- sMimeTypeMap.loadEntry("application/pgp-signature", "pgp", false);
- sMimeTypeMap.loadEntry("application/pics-rules", "prf", false);
- sMimeTypeMap.loadEntry("application/rar", "rar", false);
- sMimeTypeMap.loadEntry("application/rdf+xml", "rdf", false);
- sMimeTypeMap.loadEntry("application/rss+xml", "rss", false);
- sMimeTypeMap.loadEntry("application/zip", "zip", false);
- sMimeTypeMap.loadEntry("application/vnd.android.package-archive",
- "apk", false);
- sMimeTypeMap.loadEntry("application/vnd.cinderella", "cdy", false);
- sMimeTypeMap.loadEntry("application/vnd.ms-pki.stl", "stl", false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.database", "odb",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.formula", "odf",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.graphics", "odg",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.graphics-template",
- "otg", false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.image", "odi", false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.spreadsheet", "ods",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.spreadsheet-template",
- "ots", false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text", "odt", false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text-master", "odm",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text-template", "ott",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text-web", "oth",
- false);
- sMimeTypeMap.loadEntry("application/vnd.rim.cod", "cod", false);
- sMimeTypeMap.loadEntry("application/vnd.smaf", "mmf", false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.calc", "sdc",
- false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.draw", "sda",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.stardivision.impress", "sdd", false);
- sMimeTypeMap.loadEntry(
- "application/vnd.stardivision.impress", "sdp", false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.math", "smf",
- false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.writer", "sdw",
- false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.writer", "vor",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.stardivision.writer-global", "sgl", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.calc", "sxc",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.calc.template", "stc", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.draw", "sxd",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.draw.template", "std", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.impress", "sxi",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.impress.template", "sti", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.math", "sxm",
- false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.writer", "sxw",
- false);
- sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.writer.global", "sxg", false);
- sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.writer.template", "stw", false);
- sMimeTypeMap.loadEntry("application/vnd.visio", "vsd", false);
- sMimeTypeMap.loadEntry("application/x-abiword", "abw", false);
- sMimeTypeMap.loadEntry("application/x-apple-diskimage", "dmg",
- false);
- sMimeTypeMap.loadEntry("application/x-bcpio", "bcpio", false);
- sMimeTypeMap.loadEntry("application/x-bittorrent", "torrent",
- false);
- sMimeTypeMap.loadEntry("application/x-cdf", "cdf", false);
- sMimeTypeMap.loadEntry("application/x-cdlink", "vcd", false);
- sMimeTypeMap.loadEntry("application/x-chess-pgn", "pgn", false);
- sMimeTypeMap.loadEntry("application/x-cpio", "cpio", false);
- sMimeTypeMap.loadEntry("application/x-debian-package", "deb",
- false);
- sMimeTypeMap.loadEntry("application/x-debian-package", "udeb",
- false);
- sMimeTypeMap.loadEntry("application/x-director", "dcr", false);
- sMimeTypeMap.loadEntry("application/x-director", "dir", false);
- sMimeTypeMap.loadEntry("application/x-director", "dxr", false);
- sMimeTypeMap.loadEntry("application/x-dms", "dms", false);
- sMimeTypeMap.loadEntry("application/x-doom", "wad", false);
- sMimeTypeMap.loadEntry("application/x-dvi", "dvi", false);
- sMimeTypeMap.loadEntry("application/x-flac", "flac", false);
- sMimeTypeMap.loadEntry("application/x-font", "pfa", false);
- sMimeTypeMap.loadEntry("application/x-font", "pfb", false);
- sMimeTypeMap.loadEntry("application/x-font", "gsf", false);
- sMimeTypeMap.loadEntry("application/x-font", "pcf", false);
- sMimeTypeMap.loadEntry("application/x-font", "pcf.Z", false);
- sMimeTypeMap.loadEntry("application/x-freemind", "mm", false);
- sMimeTypeMap.loadEntry("application/x-futuresplash", "spl", false);
- sMimeTypeMap.loadEntry("application/x-gnumeric", "gnumeric", false);
- sMimeTypeMap.loadEntry("application/x-go-sgf", "sgf", false);
- sMimeTypeMap.loadEntry("application/x-graphing-calculator", "gcf",
- false);
- sMimeTypeMap.loadEntry("application/x-gtar", "gtar", false);
- sMimeTypeMap.loadEntry("application/x-gtar", "tgz", false);
- sMimeTypeMap.loadEntry("application/x-gtar", "taz", false);
- sMimeTypeMap.loadEntry("application/x-hdf", "hdf", false);
- sMimeTypeMap.loadEntry("application/x-ica", "ica", false);
- sMimeTypeMap.loadEntry("application/x-internet-signup", "ins",
- false);
- sMimeTypeMap.loadEntry("application/x-internet-signup", "isp",
- false);
- sMimeTypeMap.loadEntry("application/x-iphone", "iii", false);
- sMimeTypeMap.loadEntry("application/x-iso9660-image", "iso", false);
- sMimeTypeMap.loadEntry("application/x-jmol", "jmz", false);
- sMimeTypeMap.loadEntry("application/x-kchart", "chrt", false);
- sMimeTypeMap.loadEntry("application/x-killustrator", "kil", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skp", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skd", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skt", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skm", false);
- sMimeTypeMap.loadEntry("application/x-kpresenter", "kpr", false);
- sMimeTypeMap.loadEntry("application/x-kpresenter", "kpt", false);
- sMimeTypeMap.loadEntry("application/x-kspread", "ksp", false);
- sMimeTypeMap.loadEntry("application/x-kword", "kwd", false);
- sMimeTypeMap.loadEntry("application/x-kword", "kwt", false);
- sMimeTypeMap.loadEntry("application/x-latex", "latex", false);
- sMimeTypeMap.loadEntry("application/x-lha", "lha", false);
- sMimeTypeMap.loadEntry("application/x-lzh", "lzh", false);
- sMimeTypeMap.loadEntry("application/x-lzx", "lzx", false);
- sMimeTypeMap.loadEntry("application/x-maker", "frm", false);
- sMimeTypeMap.loadEntry("application/x-maker", "maker", false);
- sMimeTypeMap.loadEntry("application/x-maker", "frame", false);
- sMimeTypeMap.loadEntry("application/x-maker", "fb", false);
- sMimeTypeMap.loadEntry("application/x-maker", "book", false);
- sMimeTypeMap.loadEntry("application/x-maker", "fbdoc", false);
- sMimeTypeMap.loadEntry("application/x-mif", "mif", false);
- sMimeTypeMap.loadEntry("application/x-ms-wmd", "wmd", false);
- sMimeTypeMap.loadEntry("application/x-ms-wmz", "wmz", false);
- sMimeTypeMap.loadEntry("application/x-msi", "msi", false);
- sMimeTypeMap.loadEntry("application/x-ns-proxy-autoconfig", "pac",
- false);
- sMimeTypeMap.loadEntry("application/x-nwc", "nwc", false);
- sMimeTypeMap.loadEntry("application/x-object", "o", false);
- sMimeTypeMap.loadEntry("application/x-oz-application", "oza",
- false);
- sMimeTypeMap.loadEntry("application/x-pkcs7-certreqresp", "p7r",
- false);
- sMimeTypeMap.loadEntry("application/x-pkcs7-crl", "crl", false);
- sMimeTypeMap.loadEntry("application/x-quicktimeplayer", "qtl",
- false);
- sMimeTypeMap.loadEntry("application/x-shar", "shar", false);
- sMimeTypeMap.loadEntry("application/x-stuffit", "sit", false);
- sMimeTypeMap.loadEntry("application/x-sv4cpio", "sv4cpio", false);
- sMimeTypeMap.loadEntry("application/x-sv4crc", "sv4crc", false);
- sMimeTypeMap.loadEntry("application/x-tar", "tar", false);
- sMimeTypeMap.loadEntry("application/x-texinfo", "texinfo", false);
- sMimeTypeMap.loadEntry("application/x-texinfo", "texi", false);
- sMimeTypeMap.loadEntry("application/x-troff", "t", false);
- sMimeTypeMap.loadEntry("application/x-troff", "roff", false);
- sMimeTypeMap.loadEntry("application/x-troff-man", "man", false);
- sMimeTypeMap.loadEntry("application/x-ustar", "ustar", false);
- sMimeTypeMap.loadEntry("application/x-wais-source", "src", false);
- sMimeTypeMap.loadEntry("application/x-wingz", "wz", false);
- sMimeTypeMap.loadEntry(
- "application/x-webarchive", "webarchive", false); // added
- sMimeTypeMap.loadEntry("application/x-x509-ca-cert", "crt", false);
- sMimeTypeMap.loadEntry("application/x-xcf", "xcf", false);
- sMimeTypeMap.loadEntry("application/x-xfig", "fig", false);
- sMimeTypeMap.loadEntry("audio/basic", "snd", false);
- sMimeTypeMap.loadEntry("audio/midi", "mid", false);
- sMimeTypeMap.loadEntry("audio/midi", "midi", false);
- sMimeTypeMap.loadEntry("audio/midi", "kar", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mpga", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mpega", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mp2", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mp3", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "m4a", false);
- sMimeTypeMap.loadEntry("audio/mpegurl", "m3u", false);
- sMimeTypeMap.loadEntry("audio/prs.sid", "sid", false);
- sMimeTypeMap.loadEntry("audio/x-aiff", "aif", false);
- sMimeTypeMap.loadEntry("audio/x-aiff", "aiff", false);
- sMimeTypeMap.loadEntry("audio/x-aiff", "aifc", false);
- sMimeTypeMap.loadEntry("audio/x-gsm", "gsm", false);
- sMimeTypeMap.loadEntry("audio/x-mpegurl", "m3u", false);
- sMimeTypeMap.loadEntry("audio/x-ms-wma", "wma", false);
- sMimeTypeMap.loadEntry("audio/x-ms-wax", "wax", false);
- sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ra", false);
- sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "rm", false);
- sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ram", false);
- sMimeTypeMap.loadEntry("audio/x-realaudio", "ra", false);
- sMimeTypeMap.loadEntry("audio/x-scpls", "pls", false);
- sMimeTypeMap.loadEntry("audio/x-sd2", "sd2", false);
- sMimeTypeMap.loadEntry("audio/x-wav", "wav", false);
- sMimeTypeMap.loadEntry("image/bmp", "bmp", false); // added
- sMimeTypeMap.loadEntry("image/gif", "gif", false);
- sMimeTypeMap.loadEntry("image/ico", "cur", false); // added
- sMimeTypeMap.loadEntry("image/ico", "ico", false); // added
- sMimeTypeMap.loadEntry("image/ief", "ief", false);
- sMimeTypeMap.loadEntry("image/jpeg", "jpeg", false);
- sMimeTypeMap.loadEntry("image/jpeg", "jpg", false);
- sMimeTypeMap.loadEntry("image/jpeg", "jpe", false);
- sMimeTypeMap.loadEntry("image/pcx", "pcx", false);
- sMimeTypeMap.loadEntry("image/png", "png", false);
- sMimeTypeMap.loadEntry("image/svg+xml", "svg", false);
- sMimeTypeMap.loadEntry("image/svg+xml", "svgz", false);
- sMimeTypeMap.loadEntry("image/tiff", "tiff", false);
- sMimeTypeMap.loadEntry("image/tiff", "tif", false);
- sMimeTypeMap.loadEntry("image/vnd.djvu", "djvu", false);
- sMimeTypeMap.loadEntry("image/vnd.djvu", "djv", false);
- sMimeTypeMap.loadEntry("image/vnd.wap.wbmp", "wbmp", false);
- sMimeTypeMap.loadEntry("image/x-cmu-raster", "ras", false);
- sMimeTypeMap.loadEntry("image/x-coreldraw", "cdr", false);
- sMimeTypeMap.loadEntry("image/x-coreldrawpattern", "pat", false);
- sMimeTypeMap.loadEntry("image/x-coreldrawtemplate", "cdt", false);
- sMimeTypeMap.loadEntry("image/x-corelphotopaint", "cpt", false);
- sMimeTypeMap.loadEntry("image/x-icon", "ico", false);
- sMimeTypeMap.loadEntry("image/x-jg", "art", false);
- sMimeTypeMap.loadEntry("image/x-jng", "jng", false);
- sMimeTypeMap.loadEntry("image/x-ms-bmp", "bmp", false);
- sMimeTypeMap.loadEntry("image/x-photoshop", "psd", false);
- sMimeTypeMap.loadEntry("image/x-portable-anymap", "pnm", false);
- sMimeTypeMap.loadEntry("image/x-portable-bitmap", "pbm", false);
- sMimeTypeMap.loadEntry("image/x-portable-graymap", "pgm", false);
- sMimeTypeMap.loadEntry("image/x-portable-pixmap", "ppm", false);
- sMimeTypeMap.loadEntry("image/x-rgb", "rgb", false);
- sMimeTypeMap.loadEntry("image/x-xbitmap", "xbm", false);
- sMimeTypeMap.loadEntry("image/x-xpixmap", "xpm", false);
- sMimeTypeMap.loadEntry("image/x-xwindowdump", "xwd", false);
- sMimeTypeMap.loadEntry("model/iges", "igs", false);
- sMimeTypeMap.loadEntry("model/iges", "iges", false);
- sMimeTypeMap.loadEntry("model/mesh", "msh", false);
- sMimeTypeMap.loadEntry("model/mesh", "mesh", false);
- sMimeTypeMap.loadEntry("model/mesh", "silo", false);
- sMimeTypeMap.loadEntry("text/calendar", "ics", true);
- sMimeTypeMap.loadEntry("text/calendar", "icz", true);
- sMimeTypeMap.loadEntry("text/comma-separated-values", "csv", true);
- sMimeTypeMap.loadEntry("text/css", "css", true);
- sMimeTypeMap.loadEntry("text/h323", "323", true);
- sMimeTypeMap.loadEntry("text/iuls", "uls", true);
- sMimeTypeMap.loadEntry("text/mathml", "mml", true);
- // add it first so it will be the default for ExtensionFromMimeType
- sMimeTypeMap.loadEntry("text/plain", "txt", true);
- sMimeTypeMap.loadEntry("text/plain", "asc", true);
- sMimeTypeMap.loadEntry("text/plain", "text", true);
- sMimeTypeMap.loadEntry("text/plain", "diff", true);
- sMimeTypeMap.loadEntry("text/plain", "pot", true);
- sMimeTypeMap.loadEntry("text/richtext", "rtx", true);
- sMimeTypeMap.loadEntry("text/rtf", "rtf", true);
- sMimeTypeMap.loadEntry("text/texmacs", "ts", true);
- sMimeTypeMap.loadEntry("text/text", "phps", true);
- sMimeTypeMap.loadEntry("text/tab-separated-values", "tsv", true);
- sMimeTypeMap.loadEntry("text/x-bibtex", "bib", true);
- sMimeTypeMap.loadEntry("text/x-boo", "boo", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "h++", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "hpp", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "hxx", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "hh", true);
- sMimeTypeMap.loadEntry("text/x-c++src", "c++", true);
- sMimeTypeMap.loadEntry("text/x-c++src", "cpp", true);
- sMimeTypeMap.loadEntry("text/x-c++src", "cxx", true);
- sMimeTypeMap.loadEntry("text/x-chdr", "h", true);
- sMimeTypeMap.loadEntry("text/x-component", "htc", true);
- sMimeTypeMap.loadEntry("text/x-csh", "csh", true);
- sMimeTypeMap.loadEntry("text/x-csrc", "c", true);
- sMimeTypeMap.loadEntry("text/x-dsrc", "d", true);
- sMimeTypeMap.loadEntry("text/x-haskell", "hs", true);
- sMimeTypeMap.loadEntry("text/x-java", "java", true);
- sMimeTypeMap.loadEntry("text/x-literate-haskell", "lhs", true);
- sMimeTypeMap.loadEntry("text/x-moc", "moc", true);
- sMimeTypeMap.loadEntry("text/x-pascal", "p", true);
- sMimeTypeMap.loadEntry("text/x-pascal", "pas", true);
- sMimeTypeMap.loadEntry("text/x-pcs-gcd", "gcd", true);
- sMimeTypeMap.loadEntry("text/x-setext", "etx", true);
- sMimeTypeMap.loadEntry("text/x-tcl", "tcl", true);
- sMimeTypeMap.loadEntry("text/x-tex", "tex", true);
- sMimeTypeMap.loadEntry("text/x-tex", "ltx", true);
- sMimeTypeMap.loadEntry("text/x-tex", "sty", true);
- sMimeTypeMap.loadEntry("text/x-tex", "cls", true);
- sMimeTypeMap.loadEntry("text/x-vcalendar", "vcs", true);
- sMimeTypeMap.loadEntry("text/x-vcard", "vcf", true);
- sMimeTypeMap.loadEntry("video/3gpp", "3gp", false);
- sMimeTypeMap.loadEntry("video/3gpp", "3g2", false);
- sMimeTypeMap.loadEntry("video/dl", "dl", false);
- sMimeTypeMap.loadEntry("video/dv", "dif", false);
- sMimeTypeMap.loadEntry("video/dv", "dv", false);
- sMimeTypeMap.loadEntry("video/fli", "fli", false);
- sMimeTypeMap.loadEntry("video/mpeg", "mpeg", false);
- sMimeTypeMap.loadEntry("video/mpeg", "mpg", false);
- sMimeTypeMap.loadEntry("video/mpeg", "mpe", false);
- sMimeTypeMap.loadEntry("video/mp4", "mp4", false);
- sMimeTypeMap.loadEntry("video/mpeg", "VOB", false);
- sMimeTypeMap.loadEntry("video/quicktime", "qt", false);
- sMimeTypeMap.loadEntry("video/quicktime", "mov", false);
- sMimeTypeMap.loadEntry("video/vnd.mpegurl", "mxu", false);
- sMimeTypeMap.loadEntry("video/x-la-asf", "lsf", false);
- sMimeTypeMap.loadEntry("video/x-la-asf", "lsx", false);
- sMimeTypeMap.loadEntry("video/x-mng", "mng", false);
- sMimeTypeMap.loadEntry("video/x-ms-asf", "asf", false);
- sMimeTypeMap.loadEntry("video/x-ms-asf", "asx", false);
- sMimeTypeMap.loadEntry("video/x-ms-wm", "wm", false);
- sMimeTypeMap.loadEntry("video/x-ms-wmv", "wmv", false);
- sMimeTypeMap.loadEntry("video/x-ms-wmx", "wmx", false);
- sMimeTypeMap.loadEntry("video/x-ms-wvx", "wvx", false);
- sMimeTypeMap.loadEntry("video/x-msvideo", "avi", false);
- sMimeTypeMap.loadEntry("video/x-sgi-movie", "movie", false);
- sMimeTypeMap.loadEntry("x-conference/x-cooltalk", "ice", false);
- }
-
- return sMimeTypeMap;
- }
-}
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
deleted file mode 100644
index 74622b3..0000000
--- a/core/java/android/webkit/Network.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * 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.content.Context;
-import android.net.http.*;
-import android.os.*;
-import android.util.Log;
-import android.util.Config;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.util.Map;
-
-import junit.framework.Assert;
-
-class Network {
-
- private static final String LOGTAG = "network";
-
- /**
- * Static instance of a Network object.
- */
- private static Network sNetwork;
-
- /**
- * Flag to store the state of platform notifications, for the case
- * when the Network object has not been constructed yet
- */
- private static boolean sPlatformNotifications;
-
- /**
- * Reference count for platform notifications as the network class is a
- * static and can exist over multiple activities, thus over multiple
- * onPause/onResume pairs.
- */
- private static int sPlatformNotificationEnableRefCount;
-
- /**
- * Proxy username if known (used for pre-emptive proxy authentication).
- */
- private String mProxyUsername;
-
- /**
- * Proxy password if known (used for pre-emptive proxy authentication).
- */
- private String mProxyPassword;
-
- /**
- * Network request queue (requests are added from the browser thread).
- */
- private RequestQueue mRequestQueue;
-
- /**
- * SSL error handler: takes care of synchronization of multiple async
- * loaders with SSL-related problems.
- */
- private SslErrorHandler mSslErrorHandler;
-
- /**
- * HTTP authentication handler: takes care of synchronization of HTTP
- * authentication requests.
- */
- private HttpAuthHandler mHttpAuthHandler;
-
- /**
- * @return The singleton instance of the network.
- */
- public static synchronized Network getInstance(Context context) {
- if (sNetwork == null) {
- // Note Context of the Application is used here, rather than
- // the what is passed in (usually a Context derived from an
- // Activity) so the intent receivers belong to the application
- // rather than an activity - this fixes the issue where
- // Activities are created and destroyed during the lifetime of
- // an Application
- sNetwork = new Network(context.getApplicationContext());
- if (sPlatformNotifications) {
- // Adjust the ref count before calling enable as it is already
- // taken into account when the static function was called
- // directly
- --sPlatformNotificationEnableRefCount;
- enablePlatformNotifications();
- }
- }
- return sNetwork;
- }
-
-
- /**
- * Enables data state and proxy tracking
- */
- public static void enablePlatformNotifications() {
- if (++sPlatformNotificationEnableRefCount == 1) {
- if (sNetwork != null) {
- sNetwork.mRequestQueue.enablePlatformNotifications();
- } else {
- sPlatformNotifications = true;
- }
- }
- }
-
- /**
- * If platform notifications are enabled, this should be called
- * from onPause() or onStop()
- */
- public static void disablePlatformNotifications() {
- if (--sPlatformNotificationEnableRefCount == 0) {
- if (sNetwork != null) {
- sNetwork.mRequestQueue.disablePlatformNotifications();
- } else {
- sPlatformNotifications = false;
- }
- }
- }
-
- /**
- * Creates a new Network object.
- * XXX: Must be created in the same thread as WebCore!!!!!
- */
- private Network(Context context) {
- if (Config.DEBUG) {
- Assert.assertTrue(Thread.currentThread().
- getName().equals(WebViewCore.THREAD_NAME));
- }
- mSslErrorHandler = new SslErrorHandler(this);
- mHttpAuthHandler = new HttpAuthHandler(this);
-
- mRequestQueue = new RequestQueue(context);
- }
-
- /**
- * Request a url from either the network or the file system.
- * @param url The url to load.
- * @param method The http method.
- * @param headers The http headers.
- * @param postData The body of the request.
- * @param loader A LoadListener for receiving the results of the request.
- * @param isHighPriority True if this is high priority request.
- * @return True if the request was successfully queued.
- */
- public boolean requestURL(String method,
- Map<String, String> headers,
- byte [] postData,
- LoadListener loader,
- boolean isHighPriority) {
-
- String url = loader.url();
-
- // Not a valid url, return false because we won't service the request!
- if (!URLUtil.isValidUrl(url)) {
- return false;
- }
-
- // asset, file system or data stream are handled in the other code path.
- // This only handles network request.
- if (URLUtil.isAssetUrl(url) || URLUtil.isFileUrl(url) ||
- URLUtil.isDataUrl(url)) {
- return false;
- }
-
- /* FIXME: this is lame. Pass an InputStream in, rather than
- making this lame one here */
- InputStream bodyProvider = null;
- int bodyLength = 0;
- if (postData != null) {
- bodyLength = postData.length;
- bodyProvider = new ByteArrayInputStream(postData);
- }
-
- RequestQueue q = mRequestQueue;
- if (loader.isSynchronous()) {
- q = new RequestQueue(loader.getContext(), 1);
- }
-
- RequestHandle handle = q.queueRequest(
- url, loader.getWebAddress(), method, headers, loader,
- bodyProvider, bodyLength, isHighPriority);
- loader.attachRequestHandle(handle);
-
- if (loader.isSynchronous()) {
- handle.waitUntilComplete();
- loader.loadSynchronousMessages();
- q.shutdown();
- }
- return true;
- }
-
- /**
- * @return True iff there is a valid proxy set.
- */
- public boolean isValidProxySet() {
- // The proxy host and port can be set within a different thread during
- // an Intent broadcast.
- synchronized (mRequestQueue) {
- return mRequestQueue.getProxyHost() != null;
- }
- }
-
- /**
- * Get the proxy hostname.
- * @return The proxy hostname obtained from the network queue and proxy
- * settings.
- */
- public String getProxyHostname() {
- return mRequestQueue.getProxyHost().getHostName();
- }
-
- /**
- * @return The proxy username or null if none.
- */
- public synchronized String getProxyUsername() {
- return mProxyUsername;
- }
-
- /**
- * Sets the proxy username.
- * @param proxyUsername Username to use when
- * connecting through the proxy.
- */
- public synchronized void setProxyUsername(String proxyUsername) {
- if (Config.DEBUG) {
- Assert.assertTrue(isValidProxySet());
- }
-
- mProxyUsername = proxyUsername;
- }
-
- /**
- * @return The proxy password or null if none.
- */
- public synchronized String getProxyPassword() {
- return mProxyPassword;
- }
-
- /**
- * Sets the proxy password.
- * @param proxyPassword Password to use when
- * connecting through the proxy.
- */
- public synchronized void setProxyPassword(String proxyPassword) {
- if (Config.DEBUG) {
- Assert.assertTrue(isValidProxySet());
- }
-
- mProxyPassword = proxyPassword;
- }
-
- /**
- * If we need to stop loading done in a handler (here, browser frame), we
- * send a message to the handler to stop loading, and remove all loaders
- * that share the same CallbackProxy in question from all local
- * handlers (such as ssl-error and http-authentication handler).
- * @param proxy The CallbackProxy responsible for cancelling the current
- * load.
- */
- public void resetHandlersAndStopLoading(BrowserFrame frame) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "Network.resetHandlersAndStopLoading()");
- }
-
- frame.stopLoading();
- mSslErrorHandler.reset(frame);
- mHttpAuthHandler.reset(frame);
- }
-
- /**
- * Saves the state of network handlers (user SSL and HTTP-authentication
- * preferences).
- * @param outState The out-state to save (write) to.
- * @return True iff succeeds.
- */
- public boolean saveState(Bundle outState) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "Network.saveState()");
- }
-
- return mSslErrorHandler.saveState(outState);
- }
-
- /**
- * Restores the state of network handlers (user SSL and HTTP-authentication
- * preferences).
- * @param inState The in-state to load (read) from.
- * @return True iff succeeds.
- */
- public boolean restoreState(Bundle inState) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "Network.restoreState()");
- }
-
- return mSslErrorHandler.restoreState(inState);
- }
-
- /**
- * Clears user SSL-error preference table.
- */
- public void clearUserSslPrefTable() {
- mSslErrorHandler.clear();
- }
-
- /**
- * Handles SSL error(s) on the way up to the user: the user must decide
- * whether errors should be ignored or not.
- * @param loader The loader that resulted in SSL errors.
- */
- public void handleSslErrorRequest(LoadListener loader) {
- if (Config.DEBUG) Assert.assertNotNull(loader);
- if (loader != null) {
- mSslErrorHandler.handleSslErrorRequest(loader);
- }
- }
-
- /**
- * Handles authentication requests on their way up to the user (the user
- * must provide credentials).
- * @param loader The loader that resulted in an HTTP
- * authentication request.
- */
- public void handleAuthRequest(LoadListener loader) {
- if (Config.DEBUG) Assert.assertNotNull(loader);
- if (loader != null) {
- mHttpAuthHandler.handleAuthRequest(loader);
- }
- }
-
- // Performance probe
- public void startTiming() {
- mRequestQueue.startTiming();
- }
-
- public void stopTiming() {
- mRequestQueue.stopTiming();
- }
-}
diff --git a/core/java/android/webkit/PerfChecker.java b/core/java/android/webkit/PerfChecker.java
deleted file mode 100644
index 8c5f86e..0000000
--- a/core/java/android/webkit/PerfChecker.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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.os.SystemClock;
-import android.util.Log;
-
-class PerfChecker {
-
- private long mTime;
- private static final long mResponseThreshold = 2000; // 2s
-
- public PerfChecker() {
- if (false) {
- mTime = SystemClock.uptimeMillis();
- }
- }
-
- /**
- * @param what log string
- * Logs given string if mResponseThreshold time passed between either
- * instantiation or previous responseAlert call
- */
- public void responseAlert(String what) {
- if (false) {
- long upTime = SystemClock.uptimeMillis();
- long time = upTime - mTime;
- if (time > mResponseThreshold) {
- Log.w("webkit", what + " used " + time + " ms");
- }
- // Reset mTime, to permit reuse
- mTime = upTime;
- }
- }
-}
diff --git a/core/java/android/webkit/Plugin.java b/core/java/android/webkit/Plugin.java
deleted file mode 100644
index f83da99..0000000
--- a/core/java/android/webkit/Plugin.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2007 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 com.android.internal.R;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.webkit.WebView;
-
-/**
- * Represents a plugin (Java equivalent of the PluginPackageAndroid
- * C++ class in libs/WebKitLib/WebKit/WebCore/plugins/android/)
- */
-public class Plugin {
- public interface PreferencesClickHandler {
- public void handleClickEvent(Context context);
- }
-
- private String mName;
- private String mPath;
- private String mFileName;
- private String mDescription;
- private PreferencesClickHandler mHandler;
-
- public Plugin(String name,
- String path,
- String fileName,
- String description) {
- mName = name;
- mPath = path;
- mFileName = fileName;
- mDescription = description;
- mHandler = new DefaultClickHandler();
- }
-
- public String toString() {
- return mName;
- }
-
- public String getName() {
- return mName;
- }
-
- public String getPath() {
- return mPath;
- }
-
- public String getFileName() {
- return mFileName;
- }
-
- public String getDescription() {
- return mDescription;
- }
-
- public void setName(String name) {
- mName = name;
- }
-
- public void setPath(String path) {
- mPath = path;
- }
-
- public void setFileName(String fileName) {
- mFileName = fileName;
- }
-
- public void setDescription(String description) {
- mDescription = description;
- }
-
- public void setClickHandler(PreferencesClickHandler handler) {
- mHandler = handler;
- }
-
- /**
- * Invokes the click handler for this plugin.
- */
- public void dispatchClickEvent(Context context) {
- if (mHandler != null) {
- mHandler.handleClickEvent(context);
- }
- }
-
- /**
- * Default click handler. The plugins should implement their own.
- */
- private class DefaultClickHandler implements PreferencesClickHandler,
- DialogInterface.OnClickListener {
- private AlertDialog mDialog;
-
- public void handleClickEvent(Context context) {
- // Show a simple popup dialog containing the description
- // string of the plugin.
- if (mDialog == null) {
- mDialog = new AlertDialog.Builder(context)
- .setTitle(mName)
- .setMessage(mDescription)
- .setPositiveButton(R.string.ok, this)
- .setCancelable(false)
- .show();
- }
- }
-
- public void onClick(DialogInterface dialog, int which) {
- mDialog.dismiss();
- mDialog = null;
- }
- }
-}
diff --git a/core/java/android/webkit/PluginList.java b/core/java/android/webkit/PluginList.java
deleted file mode 100644
index a9d3d8c..0000000
--- a/core/java/android/webkit/PluginList.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2007 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.content.Context;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A simple list of initialized plugins. This list gets
- * populated when the plugins are initialized (at
- * browser startup, at the moment).
- */
-public class PluginList {
- private ArrayList<Plugin> mPlugins;
-
- /**
- * Public constructor. Initializes the list of plugins.
- */
- public PluginList() {
- mPlugins = new ArrayList<Plugin>();
- }
-
- /**
- * Returns the list of plugins as a java.util.List.
- */
- public synchronized List getList() {
- return mPlugins;
- }
-
- /**
- * Adds a plugin to the list.
- */
- public synchronized void addPlugin(Plugin plugin) {
- if (!mPlugins.contains(plugin)) {
- mPlugins.add(plugin);
- }
- }
-
- /**
- * Removes a plugin from the list.
- */
- public synchronized void removePlugin(Plugin plugin) {
- int location = mPlugins.indexOf(plugin);
- if (location != -1) {
- mPlugins.remove(location);
- }
- }
-
- /**
- * Clears the plugin list.
- */
- public synchronized void clear() {
- mPlugins.clear();
- }
-
- /**
- * Dispatches the click event to the appropriate plugin.
- */
- public synchronized void pluginClicked(Context context, int position) {
- try {
- Plugin plugin = mPlugins.get(position);
- plugin.dispatchClickEvent(context);
- } catch (IndexOutOfBoundsException e) {
- // This can happen if the list of plugins
- // gets changed while the pref menu is up.
- }
- }
-}
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
deleted file mode 100644
index 115434a..0000000
--- a/core/java/android/webkit/SslErrorHandler.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2007 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 junit.framework.Assert;
-
-import android.net.http.SslError;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Config;
-import android.util.Log;
-
-import java.util.LinkedList;
-import java.util.ListIterator;
-
-/**
- * SslErrorHandler: class responsible for handling SSL errors. This class is
- * passed as a parameter to BrowserCallback.displaySslErrorDialog and is meant
- * to receive the user's response.
- */
-public class SslErrorHandler extends Handler {
- /* One problem here is that there may potentially be multiple SSL errors
- * coming from mutiple loaders. Therefore, we keep a queue of loaders
- * that have SSL-related problems and process errors one by one in the
- * order they were received.
- */
-
- private static final String LOGTAG = "network";
-
- /**
- * Network.
- */
- private Network mNetwork;
-
- /**
- * Queue of loaders that experience SSL-related problems.
- */
- private LinkedList<LoadListener> mLoaderQueue;
-
- /**
- * SSL error preference table.
- */
- private Bundle mSslPrefTable;
-
- // Message id for handling the response
- private final int HANDLE_RESPONSE = 100;
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case HANDLE_RESPONSE:
- handleSslErrorResponse(msg.arg1 == 1);
- fastProcessQueuedSslErrors();
- break;
- }
- }
-
- /**
- * Creates a new error handler with an empty loader queue.
- */
- /* package */ SslErrorHandler(Network network) {
- mNetwork = network;
-
- mLoaderQueue = new LinkedList<LoadListener>();
- mSslPrefTable = new Bundle();
- }
-
- /**
- * Saves this handler's state into a map.
- * @return True iff succeeds.
- */
- /* package */ boolean saveState(Bundle outState) {
- boolean success = (outState != null);
- if (success) {
- // TODO?
- outState.putBundle("ssl-error-handler", mSslPrefTable);
- }
-
- return success;
- }
-
- /**
- * Restores this handler's state from a map.
- * @return True iff succeeds.
- */
- /* package */ boolean restoreState(Bundle inState) {
- boolean success = (inState != null);
- if (success) {
- success = inState.containsKey("ssl-error-handler");
- if (success) {
- mSslPrefTable = inState.getBundle("ssl-error-handler");
- }
- }
-
- return success;
- }
-
- /**
- * Clears SSL error preference table.
- */
- /* package */ synchronized void clear() {
- mSslPrefTable.clear();
- }
-
- /**
- * Resets the SSL error handler, removes all loaders that
- * share the same BrowserFrame.
- */
- /* package */ synchronized void reset(BrowserFrame frame) {
- ListIterator<LoadListener> i = mLoaderQueue.listIterator(0);
- while (i.hasNext()) {
- LoadListener loader = i.next();
- if (frame == loader.getFrame()) {
- i.remove();
- }
- }
- }
-
- /**
- * Handles SSL error(s) on the way up to the user.
- */
- /* package */ synchronized void handleSslErrorRequest(LoadListener loader) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "SslErrorHandler.handleSslErrorRequest(): " +
- "url=" + loader.url());
- }
-
- if (!loader.cancelled()) {
- mLoaderQueue.offer(loader);
- if (loader == mLoaderQueue.peek()) {
- fastProcessQueuedSslErrors();
- }
- }
- }
-
- /**
- * Processes queued SSL-error confirmation requests in
- * a tight loop while there is no need to ask the user.
- */
- /* package */void fastProcessQueuedSslErrors() {
- while (processNextLoader());
- }
-
- /**
- * Processes the next loader in the queue.
- * @return True iff should proceed to processing the
- * following loader in the queue
- */
- private synchronized boolean processNextLoader() {
- LoadListener loader = mLoaderQueue.peek();
- if (loader != null) {
- // if this loader has been cancelled
- if (loader.cancelled()) {
- // go to the following loader in the queue
- return true;
- }
-
- SslError error = loader.sslError();
-
- if (Config.DEBUG) {
- Assert.assertNotNull(error);
- }
-
- int primary = error.getPrimaryError();
- String host = loader.host();
-
- if (Config.DEBUG) {
- Assert.assertTrue(host != null && primary != 0);
- }
-
- if (mSslPrefTable.containsKey(host)) {
- if (primary <= mSslPrefTable.getInt(host)) {
- handleSslErrorResponse(true);
- return true;
- }
- }
-
- // if we do not have information on record, ask
- // the user (display a dialog)
- CallbackProxy proxy = loader.getFrame().getCallbackProxy();
- proxy.onReceivedSslError(this, error);
- }
-
- // the queue must be empty, stop
- return false;
- }
-
- /**
- * Proceed with the SSL certificate.
- */
- public void proceed() {
- sendMessage(obtainMessage(HANDLE_RESPONSE, 1, 0));
- }
-
- /**
- * Cancel this request and all pending requests for the WebView that had
- * the error.
- */
- public void cancel() {
- sendMessage(obtainMessage(HANDLE_RESPONSE, 0, 0));
- }
-
- /**
- * Handles SSL error(s) on the way down from the user.
- */
- /* package */ synchronized void handleSslErrorResponse(boolean proceed) {
- LoadListener loader = mLoaderQueue.poll();
- if (Config.DEBUG) {
- Assert.assertNotNull(loader);
- }
-
- if (Config.LOGV) {
- Log.v(LOGTAG, "SslErrorHandler.handleSslErrorResponse():"
- + " proceed: " + proceed
- + " url:" + loader.url());
- }
-
- if (!loader.cancelled()) {
- if (proceed) {
- // update the user's SSL error preference table
- int primary = loader.sslError().getPrimaryError();
- String host = loader.host();
-
- if (Config.DEBUG) {
- Assert.assertTrue(host != null && primary != 0);
- }
- boolean hasKey = mSslPrefTable.containsKey(host);
- if (!hasKey ||
- primary > mSslPrefTable.getInt(host)) {
- mSslPrefTable.putInt(host, new Integer(primary));
- }
-
- loader.handleSslErrorResponse(proceed);
- } else {
- loader.handleSslErrorResponse(proceed);
- mNetwork.resetHandlersAndStopLoading(loader.getFrame());
- }
- }
- }
-}
diff --git a/core/java/android/webkit/StreamLoader.java b/core/java/android/webkit/StreamLoader.java
deleted file mode 100644
index 9098307..0000000
--- a/core/java/android/webkit/StreamLoader.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2007 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.http.EventHandler;
-import android.net.http.Headers;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Config;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-
-/**
- * This abstract class is used for all content loaders that rely on streaming
- * content into the rendering engine loading framework.
- *
- * The class implements a state machine to load the content into the frame in
- * a similar manor to the way content arrives from the network. The class uses
- * messages to move from one state to the next, which enables async. loading of
- * the streamed content.
- *
- * Classes that inherit from this class must implement two methods, the first
- * method is used to setup the InputStream and notify the loading framework if
- * it can load it's content. The other method allows the derived class to add
- * additional HTTP headers to the response.
- *
- * By default, content loaded with a StreamLoader is marked with a HTTP header
- * that indicates the content should not be cached.
- *
- */
-abstract class StreamLoader extends Handler {
-
- public static final String NO_STORE = "no-store";
-
- private static final int MSG_STATUS = 100; // Send status to loader
- private static final int MSG_HEADERS = 101; // Send headers to loader
- private static final int MSG_DATA = 102; // Send data to loader
- private static final int MSG_END = 103; // Send endData to loader
-
- protected LoadListener mHandler; // loader class
- protected InputStream mDataStream; // stream to read data from
- protected long mContentLength; // content length of data
- private byte [] mData; // buffer to pass data to loader with.
-
- /**
- * Constructor. Although this class calls the LoadListener, it only calls
- * the EventHandler Interface methods. LoadListener concrete class is used
- * to avoid the penality of calling an interface.
- *
- * @param loadlistener The LoadListener to call with the data.
- */
- StreamLoader(LoadListener loadlistener) {
- mHandler = loadlistener;
- }
-
- /**
- * This method is called when the derived class should setup mDataStream,
- * and call mHandler.status() to indicate that the load can occur. If it
- * fails to setup, it should still call status() with the error code.
- *
- * @return true if stream was successfully setup
- */
- protected abstract boolean setupStreamAndSendStatus();
-
- /**
- * This method is called when the headers are about to be sent to the
- * load framework. The derived class has the opportunity to add addition
- * headers.
- *
- * @param headers Map of HTTP headers that will be sent to the loader.
- */
- abstract protected void buildHeaders(Headers headers);
-
-
- /**
- * Calling this method starts the load of the content for this StreamLoader.
- * This method simply posts a message to send the status and returns
- * immediately.
- */
- public void load() {
- if (!mHandler.isSynchronous()) {
- sendMessage(obtainMessage(MSG_STATUS));
- } else {
- // Load the stream synchronously.
- if (setupStreamAndSendStatus()) {
- // We were able to open the stream, create the array
- // to pass data to the loader
- mData = new byte[8192];
- sendHeaders();
- while (!sendData());
- closeStreamAndSendEndData();
- mHandler.loadSynchronousMessages();
- }
- }
- }
-
- /* (non-Javadoc)
- * @see android.os.Handler#handleMessage(android.os.Message)
- */
- public void handleMessage(Message msg) {
- if (Config.DEBUG && mHandler.isSynchronous()) {
- throw new AssertionError();
- }
- switch(msg.what) {
- case MSG_STATUS:
- if (setupStreamAndSendStatus()) {
- // We were able to open the stream, create the array
- // to pass data to the loader
- mData = new byte[8192];
- sendMessage(obtainMessage(MSG_HEADERS));
- }
- break;
- case MSG_HEADERS:
- sendHeaders();
- sendMessage(obtainMessage(MSG_DATA));
- break;
- case MSG_DATA:
- if (sendData()) {
- sendMessage(obtainMessage(MSG_END));
- } else {
- sendMessage(obtainMessage(MSG_DATA));
- }
- break;
- case MSG_END:
- closeStreamAndSendEndData();
- break;
- default:
- super.handleMessage(msg);
- break;
- }
- }
-
- /**
- * Construct the headers and pass them to the EventHandler.
- */
- private void sendHeaders() {
- Headers headers = new Headers();
- if (mContentLength > 0) {
- headers.setContentLength(mContentLength);
- }
- headers.setCacheControl(NO_STORE);
- buildHeaders(headers);
- mHandler.headers(headers);
- }
-
- /**
- * Read data from the stream and pass it to the EventHandler.
- * If an error occurs reading the stream, then an error is sent to the
- * EventHandler, and moves onto the next state - end of data.
- * @return True if all the data has been read. False if sendData should be
- * called again.
- */
- private boolean sendData() {
- if (mDataStream != null) {
- try {
- int amount = mDataStream.read(mData);
- if (amount > 0) {
- mHandler.data(mData, amount);
- return false;
- }
- } catch (IOException ex) {
- mHandler.error(EventHandler.FILE_ERROR,
- ex.getMessage());
- }
- }
- return true;
- }
-
- /**
- * Close the stream and inform the EventHandler that load is complete.
- */
- private void closeStreamAndSendEndData() {
- if (mDataStream != null) {
- try {
- mDataStream.close();
- } catch (IOException ex) {
- // ignore.
- }
- }
- mHandler.endData();
- }
-
-}
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java
deleted file mode 100644
index c2620a5..0000000
--- a/core/java/android/webkit/TextDialog.java
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * Copyright (C) 2007 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.content.Context;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RectShape;
-import android.os.Handler;
-import android.os.Message;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.text.method.MovementMethod;
-import android.text.method.PasswordTransformationMethod;
-import android.text.method.TextKeyListener;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewConfiguration;
-import android.widget.AbsoluteLayout.LayoutParams;
-import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-/**
- * TextDialog is a specialized version of EditText used by WebView
- * to overlay html textfields (and textareas) to use our standard
- * text editing.
- */
-/* package */ class TextDialog extends AutoCompleteTextView {
-
- private WebView mWebView;
- private boolean mSingle;
- private int mWidthSpec;
- private int mHeightSpec;
- private int mNodePointer;
- // FIXME: This is a hack for blocking unmatched key ups, in particular
- // on the enter key. The method for blocking unmatched key ups prevents
- // the shift key from working properly.
- private boolean mGotEnterDown;
- // mScrollToAccommodateCursor being set to false prevents us from scrolling
- // the cursor on screen when using the trackball to select a textfield.
- private boolean mScrollToAccommodateCursor;
- private int mMaxLength;
- // Keep track of the text before the change so we know whether we actually
- // need to send down the DOM events.
- private String mPreChange;
- // Array to store the final character added in onTextChanged, so that its
- // KeyEvents may be determined.
- private char[] mCharacter = new char[1];
- // This is used to reset the length filter when on a textfield
- // with no max length.
- // FIXME: This can be replaced with TextView.NO_FILTERS if that
- // is made public/protected.
- private static final InputFilter[] NO_FILTERS = new InputFilter[0];
- // The time of the last enter down, so we know whether to perform a long
- // press.
- private long mDownTime;
-
- private boolean mTrackballDown = false;
- private static int LONGPRESS = 1;
- private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- if (msg.what == LONGPRESS) {
- if (mTrackballDown) {
- performLongClick();
- mTrackballDown = false;
- }
- }
- }
- };
-
- /**
- * Create a new TextDialog.
- * @param context The Context for this TextDialog.
- * @param webView The WebView that created this.
- */
- /* package */ TextDialog(Context context, WebView webView) {
- super(context);
- mWebView = webView;
- ShapeDrawable background = new ShapeDrawable(new RectShape());
- Paint shapePaint = background.getPaint();
- shapePaint.setStyle(Paint.Style.STROKE);
- ColorDrawable color = new ColorDrawable(Color.WHITE);
- Drawable[] array = new Drawable[2];
- array[0] = color;
- array[1] = background;
- LayerDrawable layers = new LayerDrawable(array);
- // Hide WebCore's text behind this and allow the WebView
- // to draw its own focusring.
- setBackgroundDrawable(layers);
- // Align the text better with the text behind it, so moving
- // off of the textfield will not appear to move the text.
- setPadding(3, 2, 0, 0);
- mMaxLength = -1;
- // Turn on subpixel text, and turn off kerning, so it better matches
- // the text in webkit.
- TextPaint paint = getPaint();
- int flags = paint.getFlags() | Paint.SUBPIXEL_TEXT_FLAG |
- Paint.ANTI_ALIAS_FLAG & ~Paint.DEV_KERN_TEXT_FLAG;
- paint.setFlags(flags);
- // Set the text color to black, regardless of the theme. This ensures
- // that other applications that use embedded WebViews will properly
- // display the text in textfields.
- setTextColor(Color.BLACK);
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.isSystem()) {
- return super.dispatchKeyEvent(event);
- }
- // Treat ACTION_DOWN and ACTION MULTIPLE the same
- boolean down = event.getAction() != KeyEvent.ACTION_UP;
- int keyCode = event.getKeyCode();
- Spannable text = (Spannable) getText();
- int oldLength = text.length();
- // Normally the delete key's dom events are sent via onTextChanged.
- // However, if the length is zero, the text did not change, so we
- // go ahead and pass the key down immediately.
- if (KeyEvent.KEYCODE_DEL == keyCode && 0 == oldLength) {
- sendDomEvent(event);
- return true;
- }
-
- // For single-line textfields, return key should not be handled
- // here. Instead, the WebView is passed the key up, so it may fire a
- // submit/onClick.
- // Center key should always be passed to a potential onClick
- if ((mSingle && KeyEvent.KEYCODE_ENTER == keyCode)
- || KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
- if (isPopupShowing()) {
- super.dispatchKeyEvent(event);
- return true;
- }
- if (down) {
- if (event.getRepeatCount() == 0) {
- mGotEnterDown = true;
- mDownTime = event.getEventTime();
- // Send the keydown when the up comes, so that we have
- // a chance to handle a long press.
- } else if (mGotEnterDown && event.getEventTime() - mDownTime >
- ViewConfiguration.getLongPressTimeout()) {
- performLongClick();
- mGotEnterDown = false;
- }
- } else if (mGotEnterDown) {
- mGotEnterDown = false;
- if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
- mWebView.shortPressOnTextField();
- return true;
- }
- // If we reached here, then this is a single line textfield, and
- // the user pressed ENTER. In this case, we want to hide the
- // soft input method.
- InputMethodManager.getInstance(mContext)
- .hideSoftInputFromWindow(getWindowToken(), 0);
- sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
- sendDomEvent(event);
- }
- return true;
- }
- // Ensure there is a layout so arrow keys are handled properly.
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
- }
- int oldStart = Selection.getSelectionStart(text);
- int oldEnd = Selection.getSelectionEnd(text);
-
- boolean maxedOut = mMaxLength != -1 && oldLength == mMaxLength;
- // If we are at max length, and there is a selection rather than a
- // cursor, we need to store the text to compare later, since the key
- // may have changed the string.
- String oldText;
- if (maxedOut && oldEnd != oldStart) {
- oldText = text.toString();
- } else {
- oldText = "";
- }
- if (super.dispatchKeyEvent(event)) {
- // If the TextDialog handled the key it was either an alphanumeric
- // key, a delete, or a movement within the text. All of those are
- // ok to pass to javascript.
-
- // UNLESS there is a max length determined by the html. In that
- // case, if the string was already at the max length, an
- // alphanumeric key will be erased by the LengthFilter,
- // so do not pass down to javascript, and instead
- // return true. If it is an arrow key or a delete key, we can go
- // ahead and pass it down.
- boolean isArrowKey;
- switch(keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- isArrowKey = true;
- break;
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER:
- // For multi-line text boxes, newlines and dpad center will
- // trigger onTextChanged for key down (which will send both
- // key up and key down) but not key up.
- mGotEnterDown = true;
- default:
- isArrowKey = false;
- break;
- }
- if (maxedOut && !isArrowKey && keyCode != KeyEvent.KEYCODE_DEL) {
- if (oldEnd == oldStart) {
- // Return true so the key gets dropped.
- mScrollToAccommodateCursor = true;
- return true;
- } else if (!oldText.equals(getText().toString())) {
- // FIXME: This makes the text work properly, but it
- // does not pass down the key event, so it may not
- // work for a textfield that has the type of
- // behavior of GoogleSuggest. That said, it is
- // unlikely that a site would combine the two in
- // one textfield.
- Spannable span = (Spannable) getText();
- int newStart = Selection.getSelectionStart(span);
- int newEnd = Selection.getSelectionEnd(span);
- mWebView.replaceTextfieldText(0, oldLength, span.toString(),
- newStart, newEnd);
- mScrollToAccommodateCursor = true;
- return true;
- }
- }
- if (isArrowKey) {
- // Arrow key does not change the text, but we still want to send
- // the DOM events.
- sendDomEvent(event);
- }
- mScrollToAccommodateCursor = true;
- return true;
- }
- // FIXME: TextViews return false for up and down key events even though
- // they change the selection. Since we don't want the get out of sync
- // with WebCore's notion of the current selection, reset the selection
- // to what it was before the key event.
- Selection.setSelection(text, oldStart, oldEnd);
- // Ignore the key up event for newlines or dpad center. This prevents
- // multiple newlines in the native textarea.
- if (mGotEnterDown && !down) {
- return true;
- }
- // if it is a navigation key, pass it to WebView
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
- || keyCode == KeyEvent.KEYCODE_DPAD_UP
- || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- // WebView check the trackballtime in onKeyDown to avoid calling
- // native from both trackball and key handling. As this is called
- // from TextDialog, we always want WebView to check with native.
- // Reset trackballtime to ensure it.
- mWebView.resetTrackballTime();
- return down ? mWebView.onKeyDown(keyCode, event) : mWebView
- .onKeyUp(keyCode, event);
- }
- return false;
- }
-
- /**
- * Create a fake touch up event at (x,y) with respect to this TextDialog.
- * This is used by WebView to act as though a touch event which happened
- * before we placed the TextDialog actually hit it, so that it can place
- * the cursor accordingly.
- */
- /* package */ void fakeTouchEvent(float x, float y) {
- // We need to ensure that there is a Layout, since the Layout is used
- // in determining where to place the cursor.
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
- }
- // Create a fake touch up, which is used to place the cursor.
- MotionEvent ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP,
- x, y, 0);
- onTouchEvent(ev);
- ev.recycle();
- }
-
- /**
- * Determine whether this TextDialog currently represents the node
- * represented by ptr.
- * @param ptr Pointer to a node to compare to.
- * @return boolean Whether this TextDialog already represents the node
- * pointed to by ptr.
- */
- /* package */ boolean isSameTextField(int ptr) {
- return ptr == mNodePointer;
- }
-
- @Override
- public boolean onPreDraw() {
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
- }
- return super.onPreDraw();
- }
-
- @Override
- protected void onTextChanged(CharSequence s,int start,int before,int count){
- super.onTextChanged(s, start, before, count);
- String postChange = s.toString();
- // Prevent calls to setText from invoking onTextChanged (since this will
- // mean we are on a different textfield). Also prevent the change when
- // going from a textfield with a string of text to one with a smaller
- // limit on text length from registering the onTextChanged event.
- if (mPreChange == null || mPreChange.equals(postChange) ||
- (mMaxLength > -1 && mPreChange.length() > mMaxLength &&
- mPreChange.substring(0, mMaxLength).equals(postChange))) {
- return;
- }
- mPreChange = postChange;
- // This was simply a delete or a cut, so just delete the
- // selection.
- if (before > 0 && 0 == count) {
- mWebView.deleteSelection(start, start + before);
- // For this and all changes to the text, update our cache
- updateCachedTextfield();
- return;
- }
- // Find the last character being replaced. If it can be represented by
- // events, we will pass them to native (after replacing the beginning
- // of the changed text), so we can see javascript events.
- // Otherwise, replace the text being changed (including the last
- // character) in the textfield.
- TextUtils.getChars(s, start + count - 1, start + count, mCharacter, 0);
- KeyCharacterMap kmap =
- KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
- KeyEvent[] events = kmap.getEvents(mCharacter);
- boolean cannotUseKeyEvents = null == events;
- int charactersFromKeyEvents = cannotUseKeyEvents ? 0 : 1;
- if (count > 1 || cannotUseKeyEvents) {
- String replace = s.subSequence(start,
- start + count - charactersFromKeyEvents).toString();
- mWebView.replaceTextfieldText(start, start + before, replace,
- start + count - charactersFromKeyEvents,
- start + count - charactersFromKeyEvents);
- } else {
- // This corrects the selection which may have been affected by the
- // trackball or auto-correct.
- mWebView.setSelection(start, start + before);
- }
- updateCachedTextfield();
- if (cannotUseKeyEvents) {
- return;
- }
- int length = events.length;
- for (int i = 0; i < length; i++) {
- // We never send modifier keys to native code so don't send them
- // here either.
- if (!KeyEvent.isModifierKey(events[i].getKeyCode())) {
- sendDomEvent(events[i]);
- }
- }
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent event) {
- if (isPopupShowing()) {
- return super.onTrackballEvent(event);
- }
- int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- if (!mTrackballDown) {
- mTrackballDown = true;
- mHandler.sendEmptyMessageDelayed(LONGPRESS,
- ViewConfiguration.getLongPressTimeout());
- }
- return true;
- case MotionEvent.ACTION_UP:
- if (mTrackballDown) {
- mWebView.shortPressOnTextField();
- mTrackballDown = false;
- mHandler.removeMessages(LONGPRESS);
- }
- return true;
- case MotionEvent.ACTION_CANCEL:
- mTrackballDown = false;
- return true;
- case MotionEvent.ACTION_MOVE:
- // fall through
- }
- Spannable text = (Spannable) getText();
- MovementMethod move = getMovementMethod();
- if (move != null && getLayout() != null &&
- move.onTrackballEvent(this, text, event)) {
- // Need to pass down the selection, which has changed.
- // FIXME: This should work, but does not, so we set the selection
- // in onTextChanged.
- //int start = Selection.getSelectionStart(text);
- //int end = Selection.getSelectionEnd(text);
- //mWebView.setSelection(start, end);
- return true;
- }
- // If the user is in a textfield, and the movement method is not
- // handling the trackball events, it means they are at the end of the
- // field and continuing to move the trackball. In this case, we should
- // not scroll the cursor on screen bc the user may be attempting to
- // scroll the page, possibly in the opposite direction of the cursor.
- mScrollToAccommodateCursor = false;
- return false;
- }
-
- /**
- * Remove this TextDialog from its host WebView, and return
- * focus to the host.
- */
- /* package */ void remove() {
- // hide the soft keyboard when the edit text is out of focus
- InputMethodManager.getInstance(mContext).hideSoftInputFromWindow(
- getWindowToken(), 0);
- mHandler.removeMessages(LONGPRESS);
- mWebView.removeView(this);
- mWebView.requestFocus();
- mScrollToAccommodateCursor = false;
- }
-
- /* package */ void enableScrollOnScreen(boolean enable) {
- mScrollToAccommodateCursor = enable;
- }
-
- /* package */ void bringIntoView() {
- if (getLayout() != null) {
- bringPointIntoView(Selection.getSelectionEnd(getText()));
- }
- }
-
- @Override
- public boolean requestRectangleOnScreen(Rect rectangle) {
- if (mScrollToAccommodateCursor) {
- return super.requestRectangleOnScreen(rectangle);
- }
- return false;
- }
-
- /**
- * Send the DOM events for the specified event.
- * @param event KeyEvent to be translated into a DOM event.
- */
- private void sendDomEvent(KeyEvent event) {
- mWebView.passToJavaScript(getText().toString(), event);
- }
-
- /**
- * Always use this instead of setAdapter, as this has features specific to
- * the TextDialog.
- */
- public void setAdapterCustom(AutoCompleteAdapter adapter) {
- if (adapter != null) {
- setInputType(EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE);
- adapter.setTextView(this);
- }
- super.setAdapter(adapter);
- }
-
- /**
- * This is a special version of ArrayAdapter which changes its text size
- * to match the text size of its host TextView.
- */
- public static class AutoCompleteAdapter extends ArrayAdapter<String> {
- private TextView mTextView;
-
- public AutoCompleteAdapter(Context context, ArrayList<String> entries) {
- super(context, com.android.internal.R.layout
- .search_dropdown_item_1line, entries);
- }
-
- /**
- * {@inheritDoc}
- */
- public View getView(int position, View convertView, ViewGroup parent) {
- TextView tv =
- (TextView) super.getView(position, convertView, parent);
- if (tv != null && mTextView != null) {
- tv.setTextSize(mTextView.getTextSize());
- }
- return tv;
- }
-
- /**
- * Set the TextView so we can match its text size.
- */
- private void setTextView(TextView tv) {
- mTextView = tv;
- }
- }
-
- /**
- * Determine whether to use the system-wide password disguising method,
- * or to use none.
- * @param inPassword True if the textfield is a password field.
- */
- /* package */ void setInPassword(boolean inPassword) {
- PasswordTransformationMethod method;
- if (inPassword) {
- method = PasswordTransformationMethod.getInstance();
- setInputType(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.
- TYPE_TEXT_VARIATION_PASSWORD);
- } else {
- method = null;
- }
- setTransformationMethod(method);
- }
-
- /* package */ void setMaxLength(int maxLength) {
- mMaxLength = maxLength;
- if (-1 == maxLength) {
- setFilters(NO_FILTERS);
- } else {
- setFilters(new InputFilter[] {
- new InputFilter.LengthFilter(maxLength) });
- }
- }
-
- /**
- * Set the pointer for this node so it can be determined which node this
- * TextDialog represents.
- * @param ptr Integer representing the pointer to the node which this
- * TextDialog represents.
- */
- /* package */ void setNodePointer(int ptr) {
- mNodePointer = ptr;
- }
-
- /**
- * Determine the position and size of TextDialog, and add it to the
- * WebView's view heirarchy. All parameters are presumed to be in
- * view coordinates. Also requests Focus and sets the cursor to not
- * request to be in view.
- * @param x x-position of the textfield.
- * @param y y-position of the textfield.
- * @param width width of the textfield.
- * @param height height of the textfield.
- */
- /* package */ void setRect(int x, int y, int width, int height) {
- LayoutParams lp = (LayoutParams) getLayoutParams();
- if (null == lp) {
- lp = new LayoutParams(width, height, x, y);
- } else {
- lp.x = x;
- lp.y = y;
- lp.width = width;
- lp.height = height;
- }
- if (getParent() == null) {
- mWebView.addView(this, lp);
- } else {
- setLayoutParams(lp);
- }
- // Set up a measure spec so a layout can always be recreated.
- mWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
- mHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
- requestFocus();
- }
-
- /**
- * Set whether this is a single-line textfield or a multi-line textarea.
- * Textfields scroll horizontally, and do not handle the enter key.
- * Textareas behave oppositely.
- * Do NOT call this after calling setInPassword(true). This will result in
- * removing the password input type.
- */
- public void setSingleLine(boolean single) {
- if (mSingle != single) {
- TextKeyListener.Capitalize cap;
- int inputType = EditorInfo.TYPE_CLASS_TEXT;
- if (single) {
- cap = TextKeyListener.Capitalize.NONE;
- } else {
- cap = TextKeyListener.Capitalize.SENTENCES;
- inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
- }
- setKeyListener(TextKeyListener.getInstance(!single, cap));
- mSingle = single;
- setHorizontallyScrolling(single);
- setInputType(inputType);
- }
- }
-
- /**
- * Set the text for this TextDialog, and set the selection to (start, end)
- * @param text Text to go into this TextDialog.
- * @param start Beginning of the selection.
- * @param end End of the selection.
- */
- /* package */ void setText(CharSequence text, int start, int end) {
- mPreChange = text.toString();
- setText(text);
- Spannable span = (Spannable) getText();
- int length = span.length();
- if (end > length) {
- end = length;
- }
- if (start < 0) {
- start = 0;
- } else if (start > length) {
- start = length;
- }
- Selection.setSelection(span, start, end);
- }
-
- /**
- * Set the text to the new string, but use the old selection, making sure
- * to keep it within the new string.
- * @param text The new text to place in the textfield.
- */
- /* package */ void setTextAndKeepSelection(String text) {
- mPreChange = text.toString();
- Editable edit = (Editable) getText();
- edit.replace(0, edit.length(), text);
- updateCachedTextfield();
- }
-
- /**
- * Update the cache to reflect the current text.
- */
- /* package */ void updateCachedTextfield() {
- mWebView.updateCachedTextfield(getText().toString());
- }
-}
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
deleted file mode 100644
index 0e8144e..0000000
--- a/core/java/android/webkit/URLUtil.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * 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 java.io.UnsupportedEncodingException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import android.net.Uri;
-import android.net.ParseException;
-import android.net.WebAddress;
-import android.util.Config;
-import android.util.Log;
-
-public final class URLUtil {
-
- private static final String LOGTAG = "webkit";
-
- static final String ASSET_BASE = "file:///android_asset/";
- static final String FILE_BASE = "file://";
- static final String PROXY_BASE = "file:///cookieless_proxy/";
-
- /**
- * Cleans up (if possible) user-entered web addresses
- */
- public static String guessUrl(String inUrl) {
-
- String retVal = inUrl;
- WebAddress webAddress;
-
- Log.v(LOGTAG, "guessURL before queueRequest: " + inUrl);
-
- if (inUrl.length() == 0) return inUrl;
- if (inUrl.startsWith("about:")) return inUrl;
- // Do not try to interpret data scheme URLs
- if (inUrl.startsWith("data:")) return inUrl;
- // Do not try to interpret file scheme URLs
- if (inUrl.startsWith("file:")) return inUrl;
- // Do not try to interpret javascript scheme URLs
- if (inUrl.startsWith("javascript:")) return inUrl;
-
- // bug 762454: strip period off end of url
- if (inUrl.endsWith(".") == true) {
- inUrl = inUrl.substring(0, inUrl.length() - 1);
- }
-
- try {
- webAddress = new WebAddress(inUrl);
- } catch (ParseException ex) {
-
- if (Config.LOGV) {
- Log.v(LOGTAG, "smartUrlFilter: failed to parse url = " + inUrl);
- }
- return retVal;
- }
-
- // Check host
- if (webAddress.mHost.indexOf('.') == -1) {
- // no dot: user probably entered a bare domain. try .com
- webAddress.mHost = "www." + webAddress.mHost + ".com";
- }
- return webAddress.toString();
- }
-
- public static String composeSearchUrl(String inQuery, String template,
- String queryPlaceHolder) {
- int placeHolderIndex = template.indexOf(queryPlaceHolder);
- if (placeHolderIndex < 0) {
- return null;
- }
-
- String query;
- StringBuilder buffer = new StringBuilder();
- buffer.append(template.substring(0, placeHolderIndex));
-
- try {
- query = java.net.URLEncoder.encode(inQuery, "utf-8");
- buffer.append(query);
- } catch (UnsupportedEncodingException ex) {
- return null;
- }
-
- buffer.append(template.substring(
- placeHolderIndex + queryPlaceHolder.length()));
-
- return buffer.toString();
- }
-
- public static byte[] decode(byte[] url) throws IllegalArgumentException {
- if (url.length == 0) {
- return new byte[0];
- }
-
- // Create a new byte array with the same length to ensure capacity
- byte[] tempData = new byte[url.length];
-
- int tempCount = 0;
- for (int i = 0; i < url.length; i++) {
- byte b = url[i];
- if (b == '%') {
- if (url.length - i > 2) {
- b = (byte) (parseHex(url[i + 1]) * 16
- + parseHex(url[i + 2]));
- i += 2;
- } else {
- throw new IllegalArgumentException("Invalid format");
- }
- }
- tempData[tempCount++] = b;
- }
- byte[] retData = new byte[tempCount];
- System.arraycopy(tempData, 0, retData, 0, tempCount);
- return retData;
- }
-
- private static int parseHex(byte b) {
- if (b >= '0' && b <= '9') return (b - '0');
- if (b >= 'A' && b <= 'F') return (b - 'A' + 10);
- if (b >= 'a' && b <= 'f') return (b - 'a' + 10);
-
- throw new IllegalArgumentException("Invalid hex char '" + b + "'");
- }
-
- /**
- * @return True iff the url is an asset file.
- */
- public static boolean isAssetUrl(String url) {
- return (null != url) && url.startsWith(ASSET_BASE);
- }
-
- /**
- * @return True iff the url is an proxy url to allow cookieless network
- * requests from a file url.
- * @deprecated Cookieless proxy is no longer supported.
- */
- public static boolean isCookielessProxyUrl(String url) {
- return (null != url) && url.startsWith(PROXY_BASE);
- }
-
- /**
- * @return True iff the url is a local file.
- */
- public static boolean isFileUrl(String url) {
- return (null != url) && (url.startsWith(FILE_BASE) &&
- !url.startsWith(ASSET_BASE) &&
- !url.startsWith(PROXY_BASE));
- }
-
- /**
- * @return True iff the url is an about: url.
- */
- public static boolean isAboutUrl(String url) {
- return (null != url) && url.startsWith("about:");
- }
-
- /**
- * @return True iff the url is a data: url.
- */
- public static boolean isDataUrl(String url) {
- return (null != url) && url.startsWith("data:");
- }
-
- /**
- * @return True iff the url is a javascript: url.
- */
- public static boolean isJavaScriptUrl(String url) {
- return (null != url) && url.startsWith("javascript:");
- }
-
- /**
- * @return True iff the url is an http: url.
- */
- public static boolean isHttpUrl(String url) {
- return (null != url) &&
- (url.length() > 6) &&
- url.substring(0, 7).equalsIgnoreCase("http://");
- }
-
- /**
- * @return True iff the url is an https: url.
- */
- public static boolean isHttpsUrl(String url) {
- return (null != url) &&
- (url.length() > 7) &&
- url.substring(0, 8).equalsIgnoreCase("https://");
- }
-
- /**
- * @return True iff the url is a network url.
- */
- public static boolean isNetworkUrl(String url) {
- if (url == null || url.length() == 0) {
- return false;
- }
- return isHttpUrl(url) || isHttpsUrl(url);
- }
-
- /**
- * @return True iff the url is a content: url.
- */
- public static boolean isContentUrl(String url) {
- return (null != url) && url.startsWith("content:");
- }
-
- /**
- * @return True iff the url is valid.
- */
- public static boolean isValidUrl(String url) {
- if (url == null || url.length() == 0) {
- return false;
- }
-
- return (isAssetUrl(url) ||
- isFileUrl(url) ||
- isAboutUrl(url) ||
- isHttpUrl(url) ||
- isHttpsUrl(url) ||
- isJavaScriptUrl(url) ||
- isContentUrl(url));
- }
-
- /**
- * Strips the url of the anchor.
- */
- public static String stripAnchor(String url) {
- int anchorIndex = url.indexOf('#');
- if (anchorIndex != -1) {
- return url.substring(0, anchorIndex);
- }
- return url;
- }
-
- /**
- * Guesses canonical filename that a download would have, using
- * the URL and contentDisposition. File extension, if not defined,
- * is added based on the mimetype
- * @param url Url to the content
- * @param contentDisposition Content-Disposition HTTP header or null
- * @param mimeType Mime-type of the content or null
- *
- * @return suggested filename
- */
- public static final String guessFileName(
- String url,
- String contentDisposition,
- String mimeType) {
- String filename = null;
- String extension = null;
-
- // If we couldn't do anything with the hint, move toward the content disposition
- if (filename == null && contentDisposition != null) {
- filename = parseContentDisposition(contentDisposition);
- if (filename != null) {
- int index = filename.lastIndexOf('/') + 1;
- if (index > 0) {
- filename = filename.substring(index);
- }
- }
- }
-
- // If all the other http-related approaches failed, use the plain uri
- if (filename == null) {
- String decodedUrl = Uri.decode(url);
- if (decodedUrl != null) {
- int queryIndex = decodedUrl.indexOf('?');
- // If there is a query string strip it, same as desktop browsers
- if (queryIndex > 0) {
- decodedUrl = decodedUrl.substring(0, queryIndex);
- }
- if (!decodedUrl.endsWith("/")) {
- int index = decodedUrl.lastIndexOf('/') + 1;
- if (index > 0) {
- filename = decodedUrl.substring(index);
- }
- }
- }
- }
-
- // Finally, if couldn't get filename from URI, get a generic filename
- if (filename == null) {
- filename = "downloadfile";
- }
-
- // Split filename between base and extension
- // Add an extension if filename does not have one
- int dotIndex = filename.indexOf('.');
- if (dotIndex < 0) {
- if (mimeType != null) {
- extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
- if (extension != null) {
- extension = "." + extension;
- }
- }
- if (extension == null) {
- if (mimeType != null && mimeType.toLowerCase().startsWith("text/")) {
- if (mimeType.equalsIgnoreCase("text/html")) {
- extension = ".html";
- } else {
- extension = ".txt";
- }
- } else {
- extension = ".bin";
- }
- }
- } else {
- if (mimeType != null) {
- // Compare the last segment of the extension against the mime type.
- // If there's a mismatch, discard the entire extension.
- int lastDotIndex = filename.lastIndexOf('.');
- String typeFromExt = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
- filename.substring(lastDotIndex + 1));
- if (typeFromExt != null && !typeFromExt.equalsIgnoreCase(mimeType)) {
- extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
- if (extension != null) {
- extension = "." + extension;
- }
- }
- }
- if (extension == null) {
- extension = filename.substring(dotIndex);
- }
- filename = filename.substring(0, dotIndex);
- }
-
- return filename + extension;
- }
-
- /** Regex used to parse content-disposition headers */
- private static final Pattern CONTENT_DISPOSITION_PATTERN =
- Pattern.compile("attachment;\\s*filename\\s*=\\s*\"([^\"]*)\"");
-
- /*
- * Parse the Content-Disposition HTTP Header. The format of the header
- * is defined here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html
- * This header provides a filename for content that is going to be
- * downloaded to the file system. We only support the attachment type.
- */
- private static String parseContentDisposition(String contentDisposition) {
- try {
- Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
- if (m.find()) {
- return m.group(1);
- }
- } catch (IllegalStateException ex) {
- // This function is defined as returning null when it can't parse the header
- }
- return null;
- }
-}
diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java
deleted file mode 100644
index e1c9d61..0000000
--- a/core/java/android/webkit/UrlInterceptHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2008 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.webkit.CacheManager.CacheResult;
-import java.util.Map;
-
-public interface UrlInterceptHandler {
-
- /**
- * Given an URL, returns the CacheResult which contains the
- * surrogate response for the request, or null if the handler is
- * not interested.
- *
- * @param url URL string.
- * @param headers The headers associated with the request. May be null.
- * @return The CacheResult containing the surrogate response.
- */
- public CacheResult service(String url, Map<String, String> headers);
-}
diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java
deleted file mode 100644
index a218191..0000000
--- a/core/java/android/webkit/UrlInterceptRegistry.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2008 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.webkit.CacheManager.CacheResult;
-import android.webkit.UrlInterceptHandler;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-
-public final class UrlInterceptRegistry {
-
- private final static String LOGTAG = "intercept";
-
- private static boolean mDisabled = false;
-
- private static LinkedList mHandlerList;
-
- private static synchronized LinkedList getHandlers() {
- if(mHandlerList == null)
- mHandlerList = new LinkedList<UrlInterceptHandler>();
- return mHandlerList;
- }
-
- /**
- * set the flag to control whether url intercept is enabled or disabled
- *
- * @param disabled true to disable the cache
- */
- public static synchronized void setUrlInterceptDisabled(boolean disabled) {
- mDisabled = disabled;
- }
-
- /**
- * get the state of the url intercept, enabled or disabled
- *
- * @return return if it is disabled
- */
- public static synchronized boolean urlInterceptDisabled() {
- return mDisabled;
- }
-
- /**
- * Register a new UrlInterceptHandler. This handler will be called
- * before any that were previously registered.
- *
- * @param handler The new UrlInterceptHandler object
- * @return true if the handler was not previously registered.
- */
- public static synchronized boolean registerHandler(
- UrlInterceptHandler handler) {
- if (!getHandlers().contains(handler)) {
- getHandlers().addFirst(handler);
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Unregister a previously registered UrlInterceptHandler.
- *
- * @param handler A previously registered UrlInterceptHandler.
- * @return true if the handler was found and removed from the list.
- */
- public static synchronized boolean unregisterHandler(
- UrlInterceptHandler handler) {
- return getHandlers().remove(handler);
- }
-
- /**
- * Given an url, returns the CacheResult of the first
- * UrlInterceptHandler interested, or null if none are.
- *
- * @return A CacheResult containing surrogate content.
- */
- public static synchronized CacheResult getSurrogate(
- String url, Map<String, String> headers) {
- if (urlInterceptDisabled())
- return null;
- Iterator iter = getHandlers().listIterator();
- while (iter.hasNext()) {
- UrlInterceptHandler handler = (UrlInterceptHandler) iter.next();
- CacheResult result = handler.service(url, headers);
- if (result != null) {
- return result;
- }
- }
- return null;
- }
-}
diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java
deleted file mode 100644
index 9dea5ec..0000000
--- a/core/java/android/webkit/WebBackForwardList.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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.util.Config;
-import java.io.Serializable;
-import java.util.ArrayList;
-
-/**
- * This class contains the back/forward list for a WebView.
- * WebView.copyBackForwardList() will return a copy of this class used to
- * inspect the entries in the list.
- */
-public class WebBackForwardList implements Cloneable, Serializable {
- // Current position in the list.
- private int mCurrentIndex;
- // ArrayList of WebHistoryItems for maintaining our copy.
- private ArrayList<WebHistoryItem> mArray;
- // Flag to indicate that the list is invalid
- private boolean mClearPending;
-
- /**
- * Construct a back/forward list used by clients of WebView.
- */
- /*package*/ WebBackForwardList() {
- mCurrentIndex = -1;
- mArray = new ArrayList<WebHistoryItem>();
- }
-
- /**
- * Return the current history item. This method returns null if the list is
- * empty.
- * @return The current history item.
- */
- public synchronized WebHistoryItem getCurrentItem() {
- return getItemAtIndex(mCurrentIndex);
- }
-
- /**
- * Get the index of the current history item. This index can be used to
- * directly index into the array list.
- * @return The current index from 0...n or -1 if the list is empty.
- */
- public synchronized int getCurrentIndex() {
- return mCurrentIndex;
- }
-
- /**
- * Get the history item at the given index. The index range is from 0...n
- * where 0 is the first item and n is the last item.
- * @param index The index to retrieve.
- */
- public synchronized WebHistoryItem getItemAtIndex(int index) {
- if (index < 0 || index >= getSize()) {
- return null;
- }
- return mArray.get(index);
- }
-
- /**
- * Get the total size of the back/forward list.
- * @return The size of the list.
- */
- public synchronized int getSize() {
- return mArray.size();
- }
-
- /**
- * Mark the back/forward list as having a pending clear. This is used on the
- * UI side to mark the list as being invalid during the clearHistory method.
- */
- /*package*/ synchronized void setClearPending() {
- mClearPending = true;
- }
-
- /**
- * Return the status of the clear flag. This is used on the UI side to
- * determine if the list is valid for checking things like canGoBack.
- */
- /*package*/ synchronized boolean getClearPending() {
- return mClearPending;
- }
-
- /**
- * Add a new history item to the list. This will remove all items after the
- * current item and append the new item to the end of the list. Called from
- * the WebCore thread only. Synchronized because the UI thread may be
- * reading the array or the current index.
- * @param item A new history item.
- */
- /*package*/ synchronized void addHistoryItem(WebHistoryItem item) {
- // Update the current position because we are going to add the new item
- // in that slot.
- ++mCurrentIndex;
- // If the current position is not at the end, remove all history items
- // after the current item.
- final int size = mArray.size();
- final int newPos = mCurrentIndex;
- if (newPos != size) {
- for (int i = size - 1; i >= newPos; i--) {
- final WebHistoryItem h = mArray.remove(i);
- }
- }
- // Add the item to the list.
- mArray.add(item);
- }
-
- /**
- * Clear the back/forward list. Called from the WebCore thread.
- */
- /*package*/ synchronized void close(int nativeFrame) {
- // Clear the array first because nativeClose will call addHistoryItem
- // with the current item.
- mArray.clear();
- mCurrentIndex = -1;
- nativeClose(nativeFrame);
- // Reset the clear flag
- mClearPending = false;
- }
-
- /* Remove the item at the given index. Called by JNI only. */
- private synchronized void removeHistoryItem(int index) {
- // XXX: This is a special case. Since the callback is only triggered
- // when removing the first item, we can assert that the index is 0.
- // This lets us change the current index without having to query the
- // native BackForwardList.
- if (Config.DEBUG && (index != 0)) {
- throw new AssertionError();
- }
- final WebHistoryItem h = mArray.remove(index);
- // XXX: If we ever add another callback for removing history items at
- // any index, this will no longer be valid.
- mCurrentIndex--;
- }
-
- /**
- * Clone the entire object to be used in the UI thread by clients of
- * WebView. This creates a copy that should never be modified by any of the
- * webkit package classes.
- */
- protected synchronized WebBackForwardList clone() {
- WebBackForwardList l = new WebBackForwardList();
- if (mClearPending) {
- // If a clear is pending, return a copy with only the current item.
- l.addHistoryItem(getCurrentItem());
- return l;
- }
- l.mCurrentIndex = mCurrentIndex;
- int size = getSize();
- l.mArray = new ArrayList<WebHistoryItem>(size);
- for (int i = 0; i < size; i++) {
- // Add a copy of each WebHistoryItem
- l.mArray.add(mArray.get(i).clone());
- }
- return l;
- }
-
- /**
- * Set the new history index.
- * @param newIndex The new history index.
- */
- /*package*/ synchronized void setCurrentIndex(int newIndex) {
- mCurrentIndex = newIndex;
- }
-
- /**
- * Restore the history index.
- */
- /*package*/ static native synchronized void restoreIndex(int nativeFrame,
- int index);
-
- /* Close the native list. */
- private static native void nativeClose(int nativeFrame);
-}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
deleted file mode 100644
index f940006..0000000
--- a/core/java/android/webkit/WebChromeClient.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2008 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.graphics.Bitmap;
-import android.os.Message;
-
-public class WebChromeClient {
-
- /**
- * Tell the host application the current progress of loading a page.
- * @param view The WebView that initiated the callback.
- * @param newProgress Current page loading progress, represented by
- * an integer between 0 and 100.
- */
- public void onProgressChanged(WebView view, int newProgress) {}
-
- /**
- * Notify the host application of a change in the document title.
- * @param view The WebView that initiated the callback.
- * @param title A String containing the new title of the document.
- */
- public void onReceivedTitle(WebView view, String title) {}
-
- /**
- * Notify the host application of a new favicon for the current page.
- * @param view The WebView that initiated the callback.
- * @param icon A Bitmap containing the favicon for the current page.
- */
- public void onReceivedIcon(WebView view, Bitmap icon) {}
-
- /**
- * Request the host application to create a new Webview. The host
- * application should handle placement of the new WebView in the view
- * system. The default behavior returns null.
- * @param view The WebView that initiated the callback.
- * @param dialog True if the new window is meant to be a small dialog
- * window.
- * @param userGesture True if the request was initiated by a user gesture
- * such as clicking a link.
- * @param resultMsg The message to send when done creating a new WebView.
- * Set the new WebView through resultMsg.obj which is
- * WebView.WebViewTransport() and then call
- * resultMsg.sendToTarget();
- * @return Similar to javscript dialogs, this method should return true if
- * the client is going to handle creating a new WebView. Note that
- * the WebView will halt processing if this method returns true so
- * make sure to call resultMsg.sendToTarget(). It is undefined
- * behavior to call resultMsg.sendToTarget() after returning false
- * from this method.
- */
- public boolean onCreateWindow(WebView view, boolean dialog,
- boolean userGesture, Message resultMsg) {
- return false;
- }
-
- /**
- * Request display and focus for this WebView. This may happen due to
- * another WebView opening a link in this WebView and requesting that this
- * WebView be displayed.
- * @param view The WebView that needs to be focused.
- */
- public void onRequestFocus(WebView view) {}
-
- /**
- * Notify the host application to close the given WebView and remove it
- * from the view system if necessary. At this point, WebCore has stopped
- * any loading in this window and has removed any cross-scripting ability
- * in javascript.
- * @param window The WebView that needs to be closed.
- */
- public void onCloseWindow(WebView window) {}
-
- /**
- * Tell the client to display a javascript alert dialog. If the client
- * returns true, WebView will assume that the client will handle the
- * dialog. If the client returns false, it will continue execution.
- * @param view The WebView that initiated the callback.
- * @param url The url of the page requesting the dialog.
- * @param message Message to be displayed in the window.
- * @param result A JsResult to confirm that the user hit enter.
- * @return boolean Whether the client will handle the alert dialog.
- */
- public boolean onJsAlert(WebView view, String url, String message,
- JsResult result) {
- return false;
- }
-
- /**
- * Tell the client to display a confirm dialog to the user. If the client
- * returns true, WebView will assume that the client will handle the
- * confirm dialog and call the appropriate JsResult method. If the
- * client returns false, a default value of false will be returned to
- * javascript. The default behavior is to return false.
- * @param view The WebView that initiated the callback.
- * @param url The url of the page requesting the dialog.
- * @param message Message to be displayed in the window.
- * @param result A JsResult used to send the user's response to
- * javascript.
- * @return boolean Whether the client will handle the confirm dialog.
- */
- public boolean onJsConfirm(WebView view, String url, String message,
- JsResult result) {
- return false;
- }
-
- /**
- * Tell the client to display a prompt dialog to the user. If the client
- * returns true, WebView will assume that the client will handle the
- * prompt dialog and call the appropriate JsPromptResult method. If the
- * client returns false, a default value of false will be returned to to
- * javascript. The default behavior is to return false.
- * @param view The WebView that initiated the callback.
- * @param url The url of the page requesting the dialog.
- * @param message Message to be displayed in the window.
- * @param defaultValue The default value displayed in the prompt dialog.
- * @param result A JsPromptResult used to send the user's reponse to
- * javascript.
- * @return boolean Whether the client will handle the prompt dialog.
- */
- public boolean onJsPrompt(WebView view, String url, String message,
- String defaultValue, JsPromptResult result) {
- return false;
- }
-
- /**
- * Tell the client to display a dialog to confirm navigation away from the
- * current page. This is the result of the onbeforeunload javascript event.
- * If the client returns true, WebView will assume that the client will
- * handle the confirm dialog and call the appropriate JsResult method. If
- * the client returns false, a default value of true will be returned to
- * javascript to accept navigation away from the current page. The default
- * behavior is to return false. Setting the JsResult to true will navigate
- * away from the current page, false will cancel the navigation.
- * @param view The WebView that initiated the callback.
- * @param url The url of the page requesting the dialog.
- * @param message Message to be displayed in the window.
- * @param result A JsResult used to send the user's response to
- * javascript.
- * @return boolean Whether the client will handle the confirm dialog.
- */
- public boolean onJsBeforeUnload(WebView view, String url, String message,
- JsResult result) {
- return false;
- }
-}
diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
deleted file mode 100644
index a408e06..0000000
--- a/core/java/android/webkit/WebHistoryItem.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * 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.graphics.Bitmap;
-
-/**
- * A convenience class for accessing fields in an entry in the back/forward list
- * of a WebView. Each WebHistoryItem is a snapshot of the requested history
- * item. Each history item may be updated during the load of a page.
- * @see WebBackForwardList
- */
-public class WebHistoryItem implements Cloneable {
- // Global identifier count.
- private static int sNextId = 0;
- // Unique identifier.
- private final int mId;
- // The title of this item's document.
- private String mTitle;
- // The base url of this item.
- private String mUrl;
- // The original requested url of this item.
- private String mOriginalUrl;
- // The favicon for this item.
- private Bitmap mFavicon;
- // The pre-flattened data used for saving the state.
- private byte[] mFlattenedData;
-
- /**
- * Basic constructor that assigns a unique id to the item. Called by JNI
- * only.
- */
- private WebHistoryItem() {
- synchronized (WebHistoryItem.class) {
- mId = sNextId++;
- }
- }
-
- /**
- * Construct a new WebHistoryItem with initial flattened data.
- * @param data The pre-flattened data coming from restoreState.
- */
- /*package*/ WebHistoryItem(byte[] data) {
- mUrl = null; // This will be updated natively
- mFlattenedData = data;
- synchronized (WebHistoryItem.class) {
- mId = sNextId++;
- }
- }
-
- /**
- * Construct a clone of a WebHistoryItem from the given item.
- * @param item The history item to clone.
- */
- private WebHistoryItem(WebHistoryItem item) {
- mUrl = item.mUrl;
- mTitle = item.mTitle;
- mFlattenedData = item.mFlattenedData;
- mFavicon = item.mFavicon;
- mId = item.mId;
-}
-
- /**
- * Return an identifier for this history item. If an item is a copy of
- * another item, the identifiers will be the same even if they are not the
- * same object.
- * @return The id for this item.
- */
- public int getId() {
- return mId;
- }
-
- /**
- * Return the url of this history item. The url is the base url of this
- * history item. See getTargetUrl() for the url that is the actual target of
- * this history item.
- * @return The base url of this history item.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
- */
- public String getUrl() {
- return mUrl;
- }
-
- /**
- * Return the original url of this history item. This was the requested
- * url, the final url may be different as there might have been
- * redirects while loading the site.
- * @return The original url of this history item.
- *
- * @hide pending API Council approval
- */
- public String getOriginalUrl() {
- return mOriginalUrl;
- }
-
- /**
- * Return the document title of this history item.
- * @return The document title of this history item.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
- */
- public String getTitle() {
- return mTitle;
- }
-
- /**
- * Return the favicon of this history item or null if no favicon was found.
- * @return A Bitmap containing the favicon for this history item or null.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
- */
- public Bitmap getFavicon() {
- return mFavicon;
- }
-
- /**
- * Set the favicon.
- * @param icon A Bitmap containing the favicon for this history item.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
- */
- /*package*/ void setFavicon(Bitmap icon) {
- mFavicon = icon;
- }
-
- /**
- * Get the pre-flattened data.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
- */
- /*package*/ byte[] getFlattenedData() {
- return mFlattenedData;
- }
-
- /**
- * Inflate this item.
- * Note: The VM ensures 32-bit atomic read/write operations so we don't have
- * to synchronize this method.
- */
- /*package*/ void inflate(int nativeFrame) {
- inflate(nativeFrame, mFlattenedData);
- }
-
- /**
- * Clone the history item for use by clients of WebView.
- */
- protected synchronized WebHistoryItem clone() {
- return new WebHistoryItem(this);
- }
-
- /* Natively inflate this item, this method is called in the WebCore thread.
- */
- private native void inflate(int nativeFrame, byte[] data);
-
- /* Called by jni when the item is updated */
- private void update(String url, String originalUrl, String title,
- Bitmap favicon, byte[] data) {
- mUrl = url;
- mOriginalUrl = originalUrl;
- mTitle = title;
- mFavicon = favicon;
- mFlattenedData = data;
- }
-}
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
deleted file mode 100644
index d284f5e..0000000
--- a/core/java/android/webkit/WebIconDatabase.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * 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.os.Handler;
-import android.os.Message;
-import android.graphics.Bitmap;
-
-import java.util.Vector;
-
-/**
- * Functions for manipulating the icon database used by WebView.
- * These functions require that a WebView be constructed before being invoked
- * and WebView.getIconDatabase() will return a WebIconDatabase object. This
- * WebIconDatabase object is a single instance and all methods operate on that
- * single object.
- */
-public final class WebIconDatabase {
- // Global instance of a WebIconDatabase
- private static WebIconDatabase sIconDatabase;
- // EventHandler for handling messages before and after the WebCore thread is
- // ready.
- private final EventHandler mEventHandler = new EventHandler();
-
- // Class to handle messages before WebCore is ready
- private class EventHandler extends Handler {
- // Message ids
- static final int OPEN = 0;
- static final int CLOSE = 1;
- static final int REMOVE_ALL = 2;
- static final int REQUEST_ICON = 3;
- static final int RETAIN_ICON = 4;
- static final int RELEASE_ICON = 5;
- // Message for dispatching icon request results
- private static final int ICON_RESULT = 10;
- // Actual handler that runs in WebCore thread
- private Handler mHandler;
- // Vector of messages before the WebCore thread is ready
- private Vector<Message> mMessages = new Vector<Message>();
- // Class to handle a result dispatch
- private class IconResult {
- private final String mUrl;
- private final Bitmap mIcon;
- private final IconListener mListener;
- IconResult(String url, Bitmap icon, IconListener l) {
- mUrl = url;
- mIcon = icon;
- mListener = l;
- }
- void dispatch() {
- mListener.onReceivedIcon(mUrl, mIcon);
- }
- }
-
- @Override
- public void handleMessage(Message msg) {
- // Note: This is the message handler for the UI thread.
- switch (msg.what) {
- case ICON_RESULT:
- ((IconResult) msg.obj).dispatch();
- break;
- }
- }
-
- // Called by WebCore thread to create the actual handler
- private synchronized void createHandler() {
- if (mHandler == null) {
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // Note: This is the message handler for the WebCore
- // thread.
- switch (msg.what) {
- case OPEN:
- nativeOpen((String) msg.obj);
- break;
-
- case CLOSE:
- nativeClose();
- break;
-
- case REMOVE_ALL:
- nativeRemoveAllIcons();
- break;
-
- case REQUEST_ICON:
- IconListener l = (IconListener) msg.obj;
- String url = msg.getData().getString("url");
- Bitmap icon = nativeIconForPageUrl(url);
- if (icon != null) {
- EventHandler.this.sendMessage(
- Message.obtain(null, ICON_RESULT,
- new IconResult(url, icon, l)));
- }
- break;
-
- case RETAIN_ICON:
- nativeRetainIconForPageUrl((String) msg.obj);
- break;
-
- case RELEASE_ICON:
- nativeReleaseIconForPageUrl((String) msg.obj);
- break;
- }
- }
- };
- // Transfer all pending messages
- for (int size = mMessages.size(); size > 0; size--) {
- mHandler.sendMessage(mMessages.remove(0));
- }
- mMessages = null;
- }
- }
-
- private synchronized void postMessage(Message msg) {
- if (mMessages != null) {
- mMessages.add(msg);
- } else {
- mHandler.sendMessage(msg);
- }
- }
- }
-
- /**
- * Interface for receiving icons from the database.
- */
- public interface IconListener {
- /**
- * Called when the icon has been retrieved from the database and the
- * result is non-null.
- * @param url The url passed in the request.
- * @param icon The favicon for the given url.
- */
- public void onReceivedIcon(String url, Bitmap icon);
- }
-
- /**
- * Open a the icon database and store the icons in the given path.
- * @param path The directory path where the icon database will be stored.
- * @return True if the database was successfully opened or created in
- * the given path.
- */
- public void open(String path) {
- if (path != null) {
- mEventHandler.postMessage(
- Message.obtain(null, EventHandler.OPEN, path));
- }
- }
-
- /**
- * Close the shared instance of the icon database.
- */
- public void close() {
- mEventHandler.postMessage(
- Message.obtain(null, EventHandler.CLOSE));
- }
-
- /**
- * Removes all the icons in the database.
- */
- public void removeAllIcons() {
- mEventHandler.postMessage(
- Message.obtain(null, EventHandler.REMOVE_ALL));
- }
-
- /**
- * Request the Bitmap representing the icon for the given page
- * url. If the icon exists, the listener will be called with the result.
- * @param url The page's url.
- * @param listener An implementation on IconListener to receive the result.
- */
- public void requestIconForPageUrl(String url, IconListener listener) {
- if (listener == null || url == null) {
- return;
- }
- Message msg = Message.obtain(null, EventHandler.REQUEST_ICON, listener);
- msg.getData().putString("url", url);
- mEventHandler.postMessage(msg);
- }
-
- /**
- * Retain the icon for the given page url.
- * @param url The page's url.
- */
- public void retainIconForPageUrl(String url) {
- if (url != null) {
- mEventHandler.postMessage(
- Message.obtain(null, EventHandler.RETAIN_ICON, url));
- }
- }
-
- /**
- * Release the icon for the given page url.
- * @param url The page's url.
- */
- public void releaseIconForPageUrl(String url) {
- if (url != null) {
- mEventHandler.postMessage(
- Message.obtain(null, EventHandler.RELEASE_ICON, url));
- }
- }
-
- /**
- * Get the global instance of WebIconDatabase.
- * @return A single instance of WebIconDatabase. It will be the same
- * instance for the current process each time this method is
- * called.
- */
- public static WebIconDatabase getInstance() {
- // XXX: Must be created in the UI thread.
- if (sIconDatabase == null) {
- sIconDatabase = new WebIconDatabase();
- }
- return sIconDatabase;
- }
-
- /**
- * Create the internal handler and transfer all pending messages.
- * XXX: Called by WebCore thread only!
- */
- /*package*/ void createHandler() {
- mEventHandler.createHandler();
- }
-
- /**
- * Private constructor to avoid anyone else creating an instance.
- */
- private WebIconDatabase() {}
-
- // Native functions
- private static native void nativeOpen(String path);
- private static native void nativeClose();
- private static native void nativeRemoveAllIcons();
- private static native Bitmap nativeIconForPageUrl(String url);
- private static native void nativeRetainIconForPageUrl(String url);
- private static native void nativeReleaseIconForPageUrl(String url);
-}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
deleted file mode 100644
index 4e2b2ab..0000000
--- a/core/java/android/webkit/WebSettings.java
+++ /dev/null
@@ -1,1112 +0,0 @@
-/*
- * Copyright (C) 2007 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.content.Context;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Checkin;
-
-import java.lang.SecurityException;
-import android.content.pm.PackageManager;
-
-import java.util.Locale;
-
-/**
- * Manages settings state for a WebView. When a WebView is first created, it
- * obtains a set of default settings. These default settings will be returned
- * from any getter call. A WebSettings object obtained from
- * WebView.getSettings() is tied to the life of the WebView. If a WebView has
- * been destroyed, any method call on WebSettings will throw an
- * IllegalStateException.
- */
-public class WebSettings {
- /**
- * Enum for controlling the layout of html.
- * NORMAL means no rendering changes.
- * SINGLE_COLUMN moves all content into one column that is the width of the
- * view.
- * NARROW_COLUMNS makes all columns no wider than the screen if possible.
- */
- // XXX: These must match LayoutAlgorithm in Settings.h in WebCore.
- public enum LayoutAlgorithm {
- NORMAL,
- SINGLE_COLUMN,
- NARROW_COLUMNS
- }
-
- /**
- * Enum for specifying the text size.
- * SMALLEST is 50%
- * SMALLER is 75%
- * NORMAL is 100%
- * LARGER is 150%
- * LARGEST is 200%
- */
- public enum TextSize {
- SMALLEST(50),
- SMALLER(75),
- NORMAL(100),
- LARGER(150),
- LARGEST(200);
- TextSize(int size) {
- value = size;
- }
- int value;
- }
-
- /**
- * Default cache usage pattern Use with {@link #setCacheMode}.
- */
- public static final int LOAD_DEFAULT = -1;
-
- /**
- * Normal cache usage pattern Use with {@link #setCacheMode}.
- */
- public static final int LOAD_NORMAL = 0;
-
- /**
- * Use cache if content is there, even if expired (eg, history nav)
- * If it is not in the cache, load from network.
- * Use with {@link #setCacheMode}.
- */
- public static final int LOAD_CACHE_ELSE_NETWORK = 1;
-
- /**
- * Don't use the cache, load from network
- * Use with {@link #setCacheMode}.
- */
- public static final int LOAD_NO_CACHE = 2;
-
- /**
- * Don't use the network, load from cache only.
- * Use with {@link #setCacheMode}.
- */
- public static final int LOAD_CACHE_ONLY = 3;
-
- public enum RenderPriority {
- NORMAL,
- HIGH,
- LOW
- }
-
- // BrowserFrame used to access the native frame pointer.
- private BrowserFrame mBrowserFrame;
- // Flag to prevent multiple SYNC messages at one time.
- private boolean mSyncPending = false;
- // Custom handler that queues messages until the WebCore thread is active.
- private final EventHandler mEventHandler;
- // Private settings so we don't have to go into native code to
- // retrieve the values. After setXXX, postSync() needs to be called.
- // XXX: The default values need to match those in WebSettings.cpp
- private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
- private Context mContext;
- private TextSize mTextSize = TextSize.NORMAL;
- private String mStandardFontFamily = "sans-serif";
- private String mFixedFontFamily = "monospace";
- private String mSansSerifFontFamily = "sans-serif";
- private String mSerifFontFamily = "serif";
- private String mCursiveFontFamily = "cursive";
- private String mFantasyFontFamily = "fantasy";
- private String mDefaultTextEncoding = "Latin-1";
- private String mUserAgent;
- private boolean mUseDefaultUserAgent;
- private String mAcceptLanguage;
- private String mPluginsPath = "";
- private int mMinimumFontSize = 8;
- private int mMinimumLogicalFontSize = 8;
- private int mDefaultFontSize = 16;
- private int mDefaultFixedFontSize = 13;
- private boolean mLoadsImagesAutomatically = true;
- private boolean mBlockNetworkImage = false;
- private boolean mBlockNetworkLoads = false;
- private boolean mJavaScriptEnabled = false;
- private boolean mPluginsEnabled = false;
- private boolean mJavaScriptCanOpenWindowsAutomatically = false;
- private boolean mUseDoubleTree = false;
- private boolean mUseWideViewport = false;
- private boolean mSupportMultipleWindows = false;
- private boolean mShrinksStandaloneImagesToFit = false;
- // Don't need to synchronize the get/set methods as they
- // are basic types, also none of these values are used in
- // native WebCore code.
- private RenderPriority mRenderPriority = RenderPriority.NORMAL;
- private int mOverrideCacheMode = LOAD_DEFAULT;
- private boolean mSaveFormData = true;
- private boolean mSavePassword = true;
- private boolean mLightTouchEnabled = false;
- private boolean mNeedInitialFocus = true;
- private boolean mNavDump = false;
- private boolean mSupportZoom = true;
- private boolean mAllowFileAccess = true;
-
- // Class to handle messages before WebCore is ready.
- private class EventHandler {
- // Message id for syncing
- static final int SYNC = 0;
- // Message id for setting priority
- static final int PRIORITY = 1;
- // Actual WebCore thread handler
- private Handler mHandler;
-
- private synchronized void createHandler() {
- // as mRenderPriority can be set before thread is running, sync up
- setRenderPriority();
-
- // create a new handler
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case SYNC:
- synchronized (WebSettings.this) {
- if (mBrowserFrame.mNativeFrame != 0) {
- nativeSync(mBrowserFrame.mNativeFrame);
- }
- mSyncPending = false;
- }
- break;
-
- case PRIORITY: {
- setRenderPriority();
- break;
- }
- }
- }
- };
- }
-
- private void setRenderPriority() {
- synchronized (WebSettings.this) {
- if (mRenderPriority == RenderPriority.NORMAL) {
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_DEFAULT);
- } else if (mRenderPriority == RenderPriority.HIGH) {
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_FOREGROUND +
- android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
- } else if (mRenderPriority == RenderPriority.LOW) {
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_BACKGROUND);
- }
- }
- }
-
- /**
- * Send a message to the private queue or handler.
- */
- private synchronized boolean sendMessage(Message msg) {
- if (mHandler != null) {
- mHandler.sendMessage(msg);
- return true;
- } else {
- return false;
- }
- }
- }
-
- // User agent strings.
- private static final String DESKTOP_USERAGENT =
- "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en)"
- + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2"
- + " Safari/525.20.1";
- private static final String IPHONE_USERAGENT =
- "Mozilla/5.0 (iPhone; U; CPU iPhone 2_1 like Mac OS X; en)"
- + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2"
- + " Mobile/5F136 Safari/525.20.1";
- private static Locale sLocale;
- private static Object sLockForLocaleSettings;
-
- /**
- * Package constructor to prevent clients from creating a new settings
- * instance.
- */
- WebSettings(Context context) {
- mEventHandler = new EventHandler();
- mContext = context;
-
- if (sLockForLocaleSettings == null) {
- sLockForLocaleSettings = new Object();
- sLocale = Locale.getDefault();
- }
- mAcceptLanguage = getCurrentAcceptLanguage();
- mUserAgent = getCurrentUserAgent();
- mUseDefaultUserAgent = true;
-
- verifyNetworkAccess();
- }
-
- /**
- * Looks at sLocale and returns current AcceptLanguage String.
- * @return Current AcceptLanguage String.
- */
- private String getCurrentAcceptLanguage() {
- Locale locale;
- synchronized(sLockForLocaleSettings) {
- locale = sLocale;
- }
- StringBuffer buffer = new StringBuffer();
- final String language = locale.getLanguage();
- if (language != null) {
- buffer.append(language);
- final String country = locale.getCountry();
- if (country != null) {
- buffer.append("-");
- buffer.append(country);
- }
- }
- if (!locale.equals(Locale.US)) {
- buffer.append(", ");
- java.util.Locale us = Locale.US;
- if (us.getLanguage() != null) {
- buffer.append(us.getLanguage());
- final String country = us.getCountry();
- if (country != null) {
- buffer.append("-");
- buffer.append(country);
- }
- }
- }
-
- return buffer.toString();
- }
-
- /**
- * Looks at sLocale and mContext and returns current UserAgent String.
- * @return Current UserAgent String.
- */
- private synchronized String getCurrentUserAgent() {
- Locale locale;
- synchronized(sLockForLocaleSettings) {
- locale = sLocale;
- }
- StringBuffer buffer = new StringBuffer();
- // Add version
- final String version = Build.VERSION.RELEASE;
- if (version.length() > 0) {
- buffer.append(version);
- } else {
- // default to "1.0"
- buffer.append("1.0");
- }
- buffer.append("; ");
- final String language = locale.getLanguage();
- if (language != null) {
- buffer.append(language.toLowerCase());
- final String country = locale.getCountry();
- if (country != null) {
- buffer.append("-");
- buffer.append(country.toLowerCase());
- }
- } else {
- // default to "en"
- buffer.append("en");
- }
-
- final String model = Build.MODEL;
- if (model.length() > 0) {
- buffer.append("; ");
- buffer.append(model);
- }
- final String id = Build.ID;
- if (id.length() > 0) {
- buffer.append(" Build/");
- buffer.append(id);
- }
- final String base = mContext.getResources().getText(
- com.android.internal.R.string.web_user_agent).toString();
- return String.format(base, buffer);
- }
-
- /**
- * Enables dumping the pages navigation cache to a text file.
- */
- public void setNavDump(boolean enabled) {
- mNavDump = enabled;
- }
-
- /**
- * Returns true if dumping the navigation cache is enabled.
- */
- public boolean getNavDump() {
- return mNavDump;
- }
-
- /**
- * Set whether the WebView supports zoom
- */
- public void setSupportZoom(boolean support) {
- mSupportZoom = support;
- }
-
- /**
- * Returns whether the WebView supports zoom
- */
- public boolean supportZoom() {
- return mSupportZoom;
- }
-
- /**
- * Enable or disable file access within WebView. File access is enabled by
- * default.
- */
- public void setAllowFileAccess(boolean allow) {
- mAllowFileAccess = allow;
- }
-
- /**
- * Returns true if this WebView supports file access.
- */
- public boolean getAllowFileAccess() {
- return mAllowFileAccess;
- }
-
- /**
- * Store whether the WebView is saving form data.
- */
- public void setSaveFormData(boolean save) {
- mSaveFormData = save;
- }
-
- /**
- * Return whether the WebView is saving form data.
- */
- public boolean getSaveFormData() {
- return mSaveFormData;
- }
-
- /**
- * Store whether the WebView is saving password.
- */
- public void setSavePassword(boolean save) {
- mSavePassword = save;
- }
-
- /**
- * Return whether the WebView is saving password.
- */
- public boolean getSavePassword() {
- return mSavePassword;
- }
-
- /**
- * Set the text size of the page.
- * @param t A TextSize value for increasing or decreasing the text.
- * @see WebSettings.TextSize
- */
- public synchronized void setTextSize(TextSize t) {
- if (WebView.mLogEvent && mTextSize != t ) {
- Checkin.updateStats(mContext.getContentResolver(),
- Checkin.Stats.Tag.BROWSER_TEXT_SIZE_CHANGE, 1, 0.0);
- }
- mTextSize = t;
- postSync();
- }
-
- /**
- * Get the text size of the page.
- * @return A TextSize enum value describing the text size.
- * @see WebSettings.TextSize
- */
- public synchronized TextSize getTextSize() {
- return mTextSize;
- }
-
- /**
- * Enables using light touches to make a selection and activate mouseovers.
- */
- public void setLightTouchEnabled(boolean enabled) {
- mLightTouchEnabled = enabled;
- }
-
- /**
- * Returns true if light touches are enabled.
- */
- public boolean getLightTouchEnabled() {
- return mLightTouchEnabled;
- }
-
- /**
- * Tell the WebView to use the double tree rendering algorithm.
- * @param use True if the WebView is to use double tree rendering, false
- * otherwise.
- */
- public synchronized void setUseDoubleTree(boolean use) {
- if (mUseDoubleTree != use) {
- mUseDoubleTree = use;
- postSync();
- }
- }
-
- /**
- * Return true if the WebView is using the double tree rendering algorithm.
- * @return True if the WebView is using the double tree rendering
- * algorithm.
- */
- public synchronized boolean getUseDoubleTree() {
- return mUseDoubleTree;
- }
-
- /**
- * Tell the WebView about user-agent string.
- * @param ua 0 if the WebView should use an Android user-agent string,
- * 1 if the WebView should use a desktop user-agent string.
- *
- * @deprecated Please use setUserAgentString instead.
- */
- @Deprecated
- public synchronized void setUserAgent(int ua) {
- String uaString = null;
- if (ua == 1) {
- if (DESKTOP_USERAGENT.equals(mUserAgent)) {
- return; // do nothing
- } else {
- uaString = DESKTOP_USERAGENT;
- }
- } else if (ua == 2) {
- if (IPHONE_USERAGENT.equals(mUserAgent)) {
- return; // do nothing
- } else {
- uaString = IPHONE_USERAGENT;
- }
- } else if (ua != 0) {
- return; // do nothing
- }
- setUserAgentString(uaString);
- }
-
- /**
- * Return user-agent as int
- * @return int 0 if the WebView is using an Android user-agent string.
- * 1 if the WebView is using a desktop user-agent string.
- * -1 if the WebView is using user defined user-agent string.
- *
- * @deprecated Please use getUserAgentString instead.
- */
- @Deprecated
- public synchronized int getUserAgent() {
- if (DESKTOP_USERAGENT.equals(mUserAgent)) {
- return 1;
- } else if (IPHONE_USERAGENT.equals(mUserAgent)) {
- return 2;
- } else if (mUseDefaultUserAgent) {
- return 0;
- }
- return -1;
- }
-
- /**
- * Tell the WebView to use the wide viewport
- */
- public synchronized void setUseWideViewPort(boolean use) {
- if (mUseWideViewport != use) {
- mUseWideViewport = use;
- postSync();
- }
- }
-
- /**
- * @return True if the WebView is using a wide viewport
- */
- public synchronized boolean getUseWideViewPort() {
- return mUseWideViewport;
- }
-
- /**
- * Tell the WebView whether it supports multiple windows. TRUE means
- * that {@link WebChromeClient#onCreateWindow(WebView, boolean,
- * boolean, Message)} is implemented by the host application.
- */
- public synchronized void setSupportMultipleWindows(boolean support) {
- if (mSupportMultipleWindows != support) {
- mSupportMultipleWindows = support;
- postSync();
- }
- }
-
- /**
- * @return True if the WebView is supporting multiple windows. This means
- * that {@link WebChromeClient#onCreateWindow(WebView, boolean,
- * boolean, Message)} is implemented by the host application.
- */
- public synchronized boolean supportMultipleWindows() {
- return mSupportMultipleWindows;
- }
-
- /**
- * Set the underlying layout algorithm. This will cause a relayout of the
- * WebView.
- * @param l A LayoutAlgorithm enum specifying the algorithm to use.
- * @see WebSettings.LayoutAlgorithm
- */
- public synchronized void setLayoutAlgorithm(LayoutAlgorithm l) {
- // XXX: This will only be affective if libwebcore was built with
- // ANDROID_LAYOUT defined.
- if (mLayoutAlgorithm != l) {
- mLayoutAlgorithm = l;
- postSync();
- }
- }
-
- /**
- * Return the current layout algorithm.
- * @return LayoutAlgorithm enum value describing the layout algorithm
- * being used.
- * @see WebSettings.LayoutAlgorithm
- */
- public synchronized LayoutAlgorithm getLayoutAlgorithm() {
- return mLayoutAlgorithm;
- }
-
- /**
- * Set the standard font family name.
- * @param font A font family name.
- */
- public synchronized void setStandardFontFamily(String font) {
- if (font != null && !font.equals(mStandardFontFamily)) {
- mStandardFontFamily = font;
- postSync();
- }
- }
-
- /**
- * Get the standard font family name.
- * @return The standard font family name as a string.
- */
- public synchronized String getStandardFontFamily() {
- return mStandardFontFamily;
- }
-
- /**
- * Set the fixed font family name.
- * @param font A font family name.
- */
- public synchronized void setFixedFontFamily(String font) {
- if (font != null && !font.equals(mFixedFontFamily)) {
- mFixedFontFamily = font;
- postSync();
- }
- }
-
- /**
- * Get the fixed font family name.
- * @return The fixed font family name as a string.
- */
- public synchronized String getFixedFontFamily() {
- return mFixedFontFamily;
- }
-
- /**
- * Set the sans-serif font family name.
- * @param font A font family name.
- */
- public synchronized void setSansSerifFontFamily(String font) {
- if (font != null && !font.equals(mSansSerifFontFamily)) {
- mSansSerifFontFamily = font;
- postSync();
- }
- }
-
- /**
- * Get the sans-serif font family name.
- * @return The sans-serif font family name as a string.
- */
- public synchronized String getSansSerifFontFamily() {
- return mSansSerifFontFamily;
- }
-
- /**
- * Set the serif font family name.
- * @param font A font family name.
- */
- public synchronized void setSerifFontFamily(String font) {
- if (font != null && !font.equals(mSerifFontFamily)) {
- mSerifFontFamily = font;
- postSync();
- }
- }
-
- /**
- * Get the serif font family name.
- * @return The serif font family name as a string.
- */
- public synchronized String getSerifFontFamily() {
- return mSerifFontFamily;
- }
-
- /**
- * Set the cursive font family name.
- * @param font A font family name.
- */
- public synchronized void setCursiveFontFamily(String font) {
- if (font != null && !font.equals(mCursiveFontFamily)) {
- mCursiveFontFamily = font;
- postSync();
- }
- }
-
- /**
- * Get the cursive font family name.
- * @return The cursive font family name as a string.
- */
- public synchronized String getCursiveFontFamily() {
- return mCursiveFontFamily;
- }
-
- /**
- * Set the fantasy font family name.
- * @param font A font family name.
- */
- public synchronized void setFantasyFontFamily(String font) {
- if (font != null && !font.equals(mFantasyFontFamily)) {
- mFantasyFontFamily = font;
- postSync();
- }
- }
-
- /**
- * Get the fantasy font family name.
- * @return The fantasy font family name as a string.
- */
- public synchronized String getFantasyFontFamily() {
- return mFantasyFontFamily;
- }
-
- /**
- * Set the minimum font size.
- * @param size A non-negative integer between 1 and 72.
- * Any number outside the specified range will be pinned.
- */
- public synchronized void setMinimumFontSize(int size) {
- size = pin(size);
- if (mMinimumFontSize != size) {
- mMinimumFontSize = size;
- postSync();
- }
- }
-
- /**
- * Get the minimum font size.
- * @return A non-negative integer between 1 and 72.
- */
- public synchronized int getMinimumFontSize() {
- return mMinimumFontSize;
- }
-
- /**
- * Set the minimum logical font size.
- * @param size A non-negative integer between 1 and 72.
- * Any number outside the specified range will be pinned.
- */
- public synchronized void setMinimumLogicalFontSize(int size) {
- size = pin(size);
- if (mMinimumLogicalFontSize != size) {
- mMinimumLogicalFontSize = size;
- postSync();
- }
- }
-
- /**
- * Get the minimum logical font size.
- * @return A non-negative integer between 1 and 72.
- */
- public synchronized int getMinimumLogicalFontSize() {
- return mMinimumLogicalFontSize;
- }
-
- /**
- * Set the default font size.
- * @param size A non-negative integer between 1 and 72.
- * Any number outside the specified range will be pinned.
- */
- public synchronized void setDefaultFontSize(int size) {
- size = pin(size);
- if (mDefaultFontSize != size) {
- mDefaultFontSize = size;
- postSync();
- }
- }
-
- /**
- * Get the default font size.
- * @return A non-negative integer between 1 and 72.
- */
- public synchronized int getDefaultFontSize() {
- return mDefaultFontSize;
- }
-
- /**
- * Set the default fixed font size.
- * @param size A non-negative integer between 1 and 72.
- * Any number outside the specified range will be pinned.
- */
- public synchronized void setDefaultFixedFontSize(int size) {
- size = pin(size);
- if (mDefaultFixedFontSize != size) {
- mDefaultFixedFontSize = size;
- postSync();
- }
- }
-
- /**
- * Get the default fixed font size.
- * @return A non-negative integer between 1 and 72.
- */
- public synchronized int getDefaultFixedFontSize() {
- return mDefaultFixedFontSize;
- }
-
- /**
- * Tell the WebView to load image resources automatically.
- * @param flag True if the WebView should load images automatically.
- */
- public synchronized void setLoadsImagesAutomatically(boolean flag) {
- if (mLoadsImagesAutomatically != flag) {
- mLoadsImagesAutomatically = flag;
- postSync();
- }
- }
-
- /**
- * Return true if the WebView will load image resources automatically.
- * @return True if the WebView loads images automatically.
- */
- public synchronized boolean getLoadsImagesAutomatically() {
- return mLoadsImagesAutomatically;
- }
-
- /**
- * Tell the WebView to block network image. This is only checked when
- * getLoadsImagesAutomatically() is true.
- * @param flag True if the WebView should block network image
- */
- public synchronized void setBlockNetworkImage(boolean flag) {
- if (mBlockNetworkImage != flag) {
- mBlockNetworkImage = flag;
- postSync();
- }
- }
-
- /**
- * Return true if the WebView will block network image.
- * @return True if the WebView blocks network image.
- */
- public synchronized boolean getBlockNetworkImage() {
- return mBlockNetworkImage;
- }
-
- /**
- * @hide
- * Tell the WebView to block all network load requests.
- * @param flag True if the WebView should block all network loads
- */
- public synchronized void setBlockNetworkLoads(boolean flag) {
- if (mBlockNetworkLoads != flag) {
- mBlockNetworkLoads = flag;
- verifyNetworkAccess();
- }
- }
-
- /**
- * @hide
- * Return true if the WebView will block all network loads.
- * @return True if the WebView blocks all network loads.
- */
- public synchronized boolean getBlockNetworkLoads() {
- return mBlockNetworkLoads;
- }
-
-
- private void verifyNetworkAccess() {
- if (!mBlockNetworkLoads) {
- if (mContext.checkPermission("android.permission.INTERNET",
- android.os.Process.myPid(), 0) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException
- ("Permission denied - " +
- "application missing INTERNET permission");
- }
- }
- }
-
- /**
- * Tell the WebView to enable javascript execution.
- * @param flag True if the WebView should execute javascript.
- */
- public synchronized void setJavaScriptEnabled(boolean flag) {
- if (mJavaScriptEnabled != flag) {
- mJavaScriptEnabled = flag;
- postSync();
- }
- }
-
- /**
- * Tell the WebView to enable plugins.
- * @param flag True if the WebView should load plugins.
- */
- public synchronized void setPluginsEnabled(boolean flag) {
- if (mPluginsEnabled != flag) {
- mPluginsEnabled = flag;
- postSync();
- }
- }
-
- /**
- * Set a custom path to plugins used by the WebView. The client
- * must ensure it exists before this call.
- * @param pluginsPath String path to the directory containing plugins.
- */
- public synchronized void setPluginsPath(String pluginsPath) {
- if (pluginsPath != null && !pluginsPath.equals(mPluginsPath)) {
- mPluginsPath = pluginsPath;
- postSync();
- }
- }
-
- /**
- * Return true if javascript is enabled.
- * @return True if javascript is enabled.
- */
- public synchronized boolean getJavaScriptEnabled() {
- return mJavaScriptEnabled;
- }
-
- /**
- * Return true if plugins are enabled.
- * @return True if plugins are enabled.
- */
- public synchronized boolean getPluginsEnabled() {
- return mPluginsEnabled;
- }
-
- /**
- * Return the current path used for plugins in the WebView.
- * @return The string path to the WebView plugins.
- */
- public synchronized String getPluginsPath() {
- return mPluginsPath;
- }
-
- /**
- * Tell javascript to open windows automatically. This applies to the
- * javascript function window.open().
- * @param flag True if javascript can open windows automatically.
- */
- public synchronized void setJavaScriptCanOpenWindowsAutomatically(
- boolean flag) {
- if (mJavaScriptCanOpenWindowsAutomatically != flag) {
- mJavaScriptCanOpenWindowsAutomatically = flag;
- postSync();
- }
- }
-
- /**
- * Return true if javascript can open windows automatically.
- * @return True if javascript can open windows automatically during
- * window.open().
- */
- public synchronized boolean getJavaScriptCanOpenWindowsAutomatically() {
- return mJavaScriptCanOpenWindowsAutomatically;
- }
-
- /**
- * Set the default text encoding name to use when decoding html pages.
- * @param encoding The text encoding name.
- */
- public synchronized void setDefaultTextEncodingName(String encoding) {
- if (encoding != null && !encoding.equals(mDefaultTextEncoding)) {
- mDefaultTextEncoding = encoding;
- postSync();
- }
- }
-
- /**
- * Get the default text encoding name.
- * @return The default text encoding name as a string.
- */
- public synchronized String getDefaultTextEncodingName() {
- return mDefaultTextEncoding;
- }
-
- /**
- * Set the WebView's user-agent string. If the string "ua" is null or empty,
- * it will use the system default user-agent string.
- */
- public synchronized void setUserAgentString(String ua) {
- if (ua == null || ua.length() == 0) {
- synchronized(sLockForLocaleSettings) {
- Locale currentLocale = Locale.getDefault();
- if (!sLocale.equals(currentLocale)) {
- sLocale = currentLocale;
- mAcceptLanguage = getCurrentAcceptLanguage();
- }
- }
- ua = getCurrentUserAgent();
- mUseDefaultUserAgent = true;
- } else {
- mUseDefaultUserAgent = false;
- }
-
- if (!ua.equals(mUserAgent)) {
- mUserAgent = ua;
- postSync();
- }
- }
-
- /**
- * Return the WebView's user-agent string.
- */
- public synchronized String getUserAgentString() {
- if (DESKTOP_USERAGENT.equals(mUserAgent) ||
- IPHONE_USERAGENT.equals(mUserAgent) ||
- !mUseDefaultUserAgent) {
- return mUserAgent;
- }
-
- boolean doPostSync = false;
- synchronized(sLockForLocaleSettings) {
- Locale currentLocale = Locale.getDefault();
- if (!sLocale.equals(currentLocale)) {
- sLocale = currentLocale;
- mUserAgent = getCurrentUserAgent();
- mAcceptLanguage = getCurrentAcceptLanguage();
- doPostSync = true;
- }
- }
- if (doPostSync) {
- postSync();
- }
- return mUserAgent;
- }
-
- /* package api to grab the Accept Language string. */
- /*package*/ synchronized String getAcceptLanguage() {
- synchronized(sLockForLocaleSettings) {
- Locale currentLocale = Locale.getDefault();
- if (!sLocale.equals(currentLocale)) {
- sLocale = currentLocale;
- mAcceptLanguage = getCurrentAcceptLanguage();
- }
- }
- return mAcceptLanguage;
- }
-
- /**
- * Tell the WebView whether it needs to set a node to have focus when
- * {@link WebView#requestFocus(int, android.graphics.Rect)} is called.
- *
- * @param flag
- */
- public void setNeedInitialFocus(boolean flag) {
- if (mNeedInitialFocus != flag) {
- mNeedInitialFocus = flag;
- }
- }
-
- /* Package api to get the choice whether it needs to set initial focus. */
- /* package */ boolean getNeedInitialFocus() {
- return mNeedInitialFocus;
- }
-
- /**
- * Set the priority of the Render thread. Unlike the other settings, this
- * one only needs to be called once per process.
- *
- * @param priority RenderPriority, can be normal, high or low.
- */
- public synchronized void setRenderPriority(RenderPriority priority) {
- if (mRenderPriority != priority) {
- mRenderPriority = priority;
- mEventHandler.sendMessage(Message.obtain(null,
- EventHandler.PRIORITY));
- }
- }
-
- /**
- * Override the way the cache is used. The way the cache is used is based
- * on the navigation option. For a normal page load, the cache is checked
- * and content is re-validated as needed. When navigating back, content is
- * not revalidated, instead the content is just pulled from the cache.
- * This function allows the client to override this behavior.
- * @param mode One of the LOAD_ values.
- */
- public void setCacheMode(int mode) {
- if (mode != mOverrideCacheMode) {
- mOverrideCacheMode = mode;
- }
- }
-
- /**
- * Return the current setting for overriding the cache mode. For a full
- * description, see the {@link #setCacheMode(int)} function.
- */
- public int getCacheMode() {
- return mOverrideCacheMode;
- }
-
- /**
- * If set, webkit alternately shrinks and expands images viewed outside
- * of an HTML page to fit the screen. This conflicts with attempts by
- * the UI to zoom in and out of an image, so it is set false by default.
- * @param shrink Set true to let webkit shrink the standalone image to fit.
- * {@hide}
- */
- public void setShrinksStandaloneImagesToFit(boolean shrink) {
- if (mShrinksStandaloneImagesToFit != shrink) {
- mShrinksStandaloneImagesToFit = shrink;
- postSync();
- }
- }
-
- /**
- * Transfer messages from the queue to the new WebCoreThread. Called from
- * WebCore thread.
- */
- /*package*/
- synchronized void syncSettingsAndCreateHandler(BrowserFrame frame) {
- mBrowserFrame = frame;
- if (android.util.Config.DEBUG) {
- junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
- }
- nativeSync(frame.mNativeFrame);
- mSyncPending = false;
- mEventHandler.createHandler();
- }
-
- private int pin(int size) {
- // FIXME: 72 is just an arbitrary max text size value.
- if (size < 1) {
- return 1;
- } else if (size > 72) {
- return 72;
- }
- return size;
- }
-
- /* Post a SYNC message to handle syncing the native settings. */
- private synchronized void postSync() {
- // Only post if a sync is not pending
- if (!mSyncPending) {
- mSyncPending = mEventHandler.sendMessage(
- Message.obtain(null, EventHandler.SYNC));
- }
- }
-
- // Synchronize the native and java settings.
- private native void nativeSync(int nativeFrame);
-}
diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java
deleted file mode 100644
index e6e9994..0000000
--- a/core/java/android/webkit/WebSyncManager.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2007 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.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.util.Config;
-import android.util.Log;
-
-abstract class WebSyncManager implements Runnable {
- // message code for sync message
- private static final int SYNC_MESSAGE = 101;
- // time delay in millisec for a sync (now) message
- private static int SYNC_NOW_INTERVAL = 100; // 100 millisec
- // time delay in millisec for a sync (later) message
- private static int SYNC_LATER_INTERVAL = 5 * 60 * 1000; // 5 minutes
- // thread for syncing
- private Thread mSyncThread;
- // Name of thread
- private String mThreadName;
- // handler of the sync thread
- protected Handler mHandler;
- // database for the persistent storage
- protected WebViewDatabase mDataBase;
- // Ref count for calls to start/stop sync
- private int mStartSyncRefCount;
- // log tag
- protected static final String LOGTAG = "websync";
-
- private class SyncHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == SYNC_MESSAGE) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "*** WebSyncManager sync ***");
- }
- syncFromRamToFlash();
-
- // send a delayed message to request sync later
- Message newmsg = obtainMessage(SYNC_MESSAGE);
- sendMessageDelayed(newmsg, SYNC_LATER_INTERVAL);
- }
- }
- }
-
- protected WebSyncManager(Context context, String name) {
- mThreadName = name;
- if (context != null) {
- mDataBase = WebViewDatabase.getInstance(context);
- mSyncThread = new Thread(this);
- mSyncThread.setName(mThreadName);
- mSyncThread.start();
- } else {
- throw new IllegalStateException(
- "WebSyncManager can't be created without context");
- }
- }
-
- protected Object clone() throws CloneNotSupportedException {
- throw new CloneNotSupportedException("doesn't implement Cloneable");
- }
-
- public void run() {
- // prepare Looper for sync handler
- Looper.prepare();
- mHandler = new SyncHandler();
- onSyncInit();
- // lower the priority after onSyncInit() is done
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
- Message msg = mHandler.obtainMessage(SYNC_MESSAGE);
- mHandler.sendMessageDelayed(msg, SYNC_LATER_INTERVAL);
-
- Looper.loop();
- }
-
- /**
- * sync() forces sync manager to sync now
- */
- public void sync() {
- if (Config.LOGV) {
- Log.v(LOGTAG, "*** WebSyncManager sync ***");
- }
- if (mHandler == null) {
- return;
- }
- mHandler.removeMessages(SYNC_MESSAGE);
- Message msg = mHandler.obtainMessage(SYNC_MESSAGE);
- mHandler.sendMessageDelayed(msg, SYNC_NOW_INTERVAL);
- }
-
- /**
- * resetSync() resets sync manager's timer
- */
- public void resetSync() {
- if (Config.LOGV) {
- Log.v(LOGTAG, "*** WebSyncManager resetSync ***");
- }
- if (mHandler == null) {
- return;
- }
- mHandler.removeMessages(SYNC_MESSAGE);
- Message msg = mHandler.obtainMessage(SYNC_MESSAGE);
- mHandler.sendMessageDelayed(msg, SYNC_LATER_INTERVAL);
- }
-
- /**
- * startSync() requests sync manager to start sync
- */
- public void startSync() {
- if (Config.LOGV) {
- Log.v(LOGTAG, "*** WebSyncManager startSync ***, Ref count:" +
- mStartSyncRefCount);
- }
- if (mHandler == null) {
- return;
- }
- if (++mStartSyncRefCount == 1) {
- Message msg = mHandler.obtainMessage(SYNC_MESSAGE);
- mHandler.sendMessageDelayed(msg, SYNC_LATER_INTERVAL);
- }
- }
-
- /**
- * stopSync() requests sync manager to stop sync. remove any SYNC_MESSAGE in
- * the queue to break the sync loop
- */
- public void stopSync() {
- if (Config.LOGV) {
- Log.v(LOGTAG, "*** WebSyncManager stopSync ***, Ref count:" +
- mStartSyncRefCount);
- }
- if (mHandler == null) {
- return;
- }
- if (--mStartSyncRefCount == 0) {
- mHandler.removeMessages(SYNC_MESSAGE);
- }
- }
-
- protected void onSyncInit() {
- }
-
- abstract void syncFromRamToFlash();
-}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
deleted file mode 100644
index 417b657..0000000
--- a/core/java/android/webkit/WebView.java
+++ /dev/null
@@ -1,5338 +0,0 @@
-/*
- * 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.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Picture;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.net.http.SslCertificate;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.provider.Checkin;
-import android.text.IClipboard;
-import android.text.Selection;
-import android.text.Spannable;
-import android.util.AttributeSet;
-import android.util.Config;
-import android.util.EventLog;
-import android.util.Log;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.SoundEffectConstants;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.ViewTreeObserver;
-import android.view.inputmethod.InputMethodManager;
-import android.webkit.TextDialog.AutoCompleteAdapter;
-import android.webkit.WebViewCore.EventHub;
-import android.widget.AbsoluteLayout;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.RelativeLayout;
-import android.widget.Scroller;
-import android.widget.Toast;
-import android.widget.ZoomControls;
-import android.widget.ZoomRingController;
-import android.widget.FrameLayout;
-import android.widget.AdapterView.OnItemClickListener;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * <p>A View that displays web pages. This class is the basis upon which you
- * can roll your own web browser or simply display some online content within your Activity.
- * It uses the WebKit rendering engine to display
- * web pages and includes methods to navigate forward and backward
- * through a history, zoom in and out, perform text searches and more.</p>
- * <p>Note that, in order for your Activity to access the Internet and load web pages
- * in a WebView, you must add the <var>INTERNET</var> permissions to your
- * Android Manifest file:</p>
- * <pre>&lt;uses-permission android:name="android.permission.INTERNET" /></pre>
- * <p>This must be a child of the <code>&lt;manifest></code> element.</p>
- */
-public class WebView extends AbsoluteLayout
- implements ViewTreeObserver.OnGlobalFocusChangeListener,
- ViewGroup.OnHierarchyChangeListener {
-
- // if AUTO_REDRAW_HACK is true, then the CALL key will toggle redrawing
- // the screen all-the-time. Good for profiling our drawing code
- static private final boolean AUTO_REDRAW_HACK = false;
- // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
- private boolean mAutoRedraw;
-
- // keep debugging parameters near the top of the file
- static final String LOGTAG = "webview";
- static final boolean DEBUG = false;
- static final boolean LOGV_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
-
- private class ExtendedZoomControls extends FrameLayout {
- public ExtendedZoomControls(Context context, AttributeSet attrs) {
- super(context, attrs);
- LayoutInflater inflater = (LayoutInflater)
- context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(com.android.internal.R.layout.zoom_magnify, this, true);
- mZoomControls = (ZoomControls) findViewById(com.android.internal.R.id.zoomControls);
- mZoomMagnify = (ImageView) findViewById(com.android.internal.R.id.zoomMagnify);
- }
-
- public void show(boolean showZoom, boolean canZoomOut) {
- mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE);
- mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE);
- fade(View.VISIBLE, 0.0f, 1.0f);
- }
-
- public void hide() {
- fade(View.GONE, 1.0f, 0.0f);
- }
-
- private void fade(int visibility, float startAlpha, float endAlpha) {
- AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha);
- anim.setDuration(500);
- startAnimation(anim);
- setVisibility(visibility);
- }
-
- public void setIsZoomMagnifyEnabled(boolean isEnabled) {
- mZoomMagnify.setEnabled(isEnabled);
- }
-
- public boolean hasFocus() {
- return mZoomControls.hasFocus() || mZoomMagnify.hasFocus();
- }
-
- public void setOnZoomInClickListener(OnClickListener listener) {
- mZoomControls.setOnZoomInClickListener(listener);
- }
-
- public void setOnZoomOutClickListener(OnClickListener listener) {
- mZoomControls.setOnZoomOutClickListener(listener);
- }
-
- public void setOnZoomMagnifyClickListener(OnClickListener listener) {
- mZoomMagnify.setOnClickListener(listener);
- }
-
- ZoomControls mZoomControls;
- ImageView mZoomMagnify;
- }
-
- /**
- * Transportation object for returning WebView across thread boundaries.
- */
- public class WebViewTransport {
- private WebView mWebview;
-
- /**
- * Set the WebView to the transportation object.
- * @param webview The WebView to transport.
- */
- public synchronized void setWebView(WebView webview) {
- mWebview = webview;
- }
-
- /**
- * Return the WebView object.
- * @return WebView The transported WebView object.
- */
- public synchronized WebView getWebView() {
- return mWebview;
- }
- }
-
- // A final CallbackProxy shared by WebViewCore and BrowserFrame.
- private final CallbackProxy mCallbackProxy;
-
- private final WebViewDatabase mDatabase;
-
- // SSL certificate for the main top-level page (if secure)
- private SslCertificate mCertificate;
-
- // Native WebView pointer that is 0 until the native object has been
- // created.
- private int mNativeClass;
- // This would be final but it needs to be set to null when the WebView is
- // destroyed.
- private WebViewCore mWebViewCore;
- // Handler for dispatching UI messages.
- /* package */ final Handler mPrivateHandler = new PrivateHandler();
- private TextDialog mTextEntry;
- // Used to ignore changes to webkit text that arrives to the UI side after
- // more key events.
- private int mTextGeneration;
-
- // The list of loaded plugins.
- private static PluginList sPluginList;
-
- /**
- * Position of the last touch event.
- */
- private float mLastTouchX;
- private float mLastTouchY;
-
- /**
- * Time of the last touch event.
- */
- private long mLastTouchTime;
-
- /**
- * Time of the last time sending touch event to WebViewCore
- */
- private long mLastSentTouchTime;
-
- /**
- * The minimum elapsed time before sending another ACTION_MOVE event to
- * WebViewCore
- */
- private static final int TOUCH_SENT_INTERVAL = 100;
-
- /**
- * Helper class to get velocity for fling
- */
- VelocityTracker mVelocityTracker;
-
- private static boolean mShowZoomRingTutorial = true;
- private static final int ZOOM_RING_TUTORIAL_DURATION = 3000;
-
- /**
- * Touch mode
- */
- private int mTouchMode = TOUCH_DONE_MODE;
- private static final int TOUCH_INIT_MODE = 1;
- private static final int TOUCH_DRAG_START_MODE = 2;
- private static final int TOUCH_DRAG_MODE = 3;
- private static final int TOUCH_SHORTPRESS_START_MODE = 4;
- private static final int TOUCH_SHORTPRESS_MODE = 5;
- private static final int TOUCH_DOUBLECLICK_MODE = 6;
- private static final int TOUCH_DONE_MODE = 7;
- private static final int TOUCH_SELECT_MODE = 8;
- // touch mode values specific to scale+scroll
- private static final int FIRST_SCROLL_ZOOM = 9;
- private static final int SCROLL_ZOOM_ANIMATION_IN = 9;
- private static final int SCROLL_ZOOM_ANIMATION_OUT = 10;
- private static final int SCROLL_ZOOM_OUT = 11;
- private static final int LAST_SCROLL_ZOOM = 11;
- // end of touch mode values specific to scale+scroll
-
- // Whether to forward the touch events to WebCore
- private boolean mForwardTouchEvents = false;
-
- // Whether we are in the drag tap mode, which exists starting at the second
- // tap's down, through its move, and includes its up. These events should be
- // given to the method on the zoom controller.
- private boolean mInZoomTapDragMode = false;
-
- // Whether to prevent drag during touch. The initial value depends on
- // mForwardTouchEvents. If WebCore wants touch events, we assume it will
- // take control of touch events unless it says no for touch down event.
- private boolean mPreventDrag;
-
- // If updateTextEntry gets called while we are out of focus, use this
- // variable to remember to do it next time we gain focus.
- private boolean mNeedsUpdateTextEntry = false;
-
- // Whether or not to draw the focus ring.
- private boolean mDrawFocusRing = true;
-
- /**
- * Customizable constant
- */
- // pre-computed square of ViewConfiguration.getTouchSlop()
- private int mTouchSlopSquare;
- // This should be ViewConfiguration.getTapTimeout()
- // But system time out is 100ms, which is too short for the browser.
- // In the browser, if it switches out of tap too soon, jump tap won't work.
- private static final int TAP_TIMEOUT = 200;
- // The duration in milliseconds we will wait to see if it is a double tap.
- private static final int DOUBLE_TAP_TIMEOUT = 250;
- // This should be ViewConfiguration.getLongPressTimeout()
- // But system time out is 500ms, which is too short for the browser.
- // With a short timeout, it's difficult to treat trigger a short press.
- private static final int LONG_PRESS_TIMEOUT = 1000;
- // needed to avoid flinging after a pause of no movement
- private static final int MIN_FLING_TIME = 250;
- // The time that the Zoom Controls are visible before fading away
- private static final long ZOOM_CONTROLS_TIMEOUT =
- ViewConfiguration.getZoomControlsTimeout();
- // The amount of content to overlap between two screens when going through
- // pages with the space bar, in pixels.
- private static final int PAGE_SCROLL_OVERLAP = 24;
-
- /**
- * These prevent calling requestLayout if either dimension is fixed. This
- * depends on the layout parameters and the measure specs.
- */
- boolean mWidthCanMeasure;
- boolean mHeightCanMeasure;
-
- // Remember the last dimensions we sent to the native side so we can avoid
- // sending the same dimensions more than once.
- int mLastWidthSent;
- int mLastHeightSent;
-
- private int mContentWidth; // cache of value from WebViewCore
- private int mContentHeight; // cache of value from WebViewCore
-
- static int MAX_FLOAT_CONTENT_WIDTH = 480;
- private int mMinContentWidth;
-
- // Need to have the separate control for horizontal and vertical scrollbar
- // style than the View's single scrollbar style
- private boolean mOverlayHorizontalScrollbar = true;
- private boolean mOverlayVerticalScrollbar = false;
-
- // our standard speed. this way small distances will be traversed in less
- // time than large distances, but we cap the duration, so that very large
- // distances won't take too long to get there.
- private static final int STD_SPEED = 480; // pixels per second
- // time for the longest scroll animation
- private static final int MAX_DURATION = 750; // milliseconds
- private Scroller mScroller;
-
- private boolean mWrapContent;
-
- // The View containing the zoom controls
- private ExtendedZoomControls mZoomControls;
- private Runnable mZoomControlRunnable;
-
- // true if we should call webcore to draw the content, false means we have
- // requested something but it isn't ready to draw yet.
- private WebViewCore.FocusData mFocusData;
- /**
- * Private message ids
- */
- private static final int REMEMBER_PASSWORD = 1;
- private static final int NEVER_REMEMBER_PASSWORD = 2;
- private static final int SWITCH_TO_SHORTPRESS = 3;
- private static final int SWITCH_TO_LONGPRESS = 4;
- private static final int RELEASE_SINGLE_TAP = 5;
- private static final int UPDATE_TEXT_ENTRY_ADAPTER = 6;
- private static final int SWITCH_TO_ENTER = 7;
- private static final int RESUME_WEBCORE_UPDATE = 8;
- private static final int DISMISS_ZOOM_RING_TUTORIAL = 9;
-
- //! arg1=x, arg2=y
- static final int SCROLL_TO_MSG_ID = 10;
- static final int SCROLL_BY_MSG_ID = 11;
- //! arg1=x, arg2=y
- static final int SPAWN_SCROLL_TO_MSG_ID = 12;
- //! arg1=x, arg2=y
- static final int SYNC_SCROLL_TO_MSG_ID = 13;
- static final int NEW_PICTURE_MSG_ID = 14;
- static final int UPDATE_TEXT_ENTRY_MSG_ID = 15;
- static final int WEBCORE_INITIALIZED_MSG_ID = 16;
- static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 17;
- static final int DID_FIRST_LAYOUT_MSG_ID = 18;
- static final int RECOMPUTE_FOCUS_MSG_ID = 19;
- static final int NOTIFY_FOCUS_SET_MSG_ID = 20;
- static final int MARK_NODE_INVALID_ID = 21;
- static final int UPDATE_CLIPBOARD = 22;
- static final int LONG_PRESS_ENTER = 23;
- static final int PREVENT_TOUCH_ID = 24;
- static final int WEBCORE_NEED_TOUCH_EVENTS = 25;
- // obj=Rect in doc coordinates
- static final int INVAL_RECT_MSG_ID = 26;
-
- static final String[] HandlerDebugString = {
- "REMEMBER_PASSWORD", // = 1;
- "NEVER_REMEMBER_PASSWORD", // = 2;
- "SWITCH_TO_SHORTPRESS", // = 3;
- "SWITCH_TO_LONGPRESS", // = 4;
- "RELEASE_SINGLE_TAP", // = 5;
- "UPDATE_TEXT_ENTRY_ADAPTER", // = 6;
- "SWITCH_TO_ENTER", // = 7;
- "RESUME_WEBCORE_UPDATE", // = 8;
- "9",
- "SCROLL_TO_MSG_ID", // = 10;
- "SCROLL_BY_MSG_ID", // = 11;
- "SPAWN_SCROLL_TO_MSG_ID", // = 12;
- "SYNC_SCROLL_TO_MSG_ID", // = 13;
- "NEW_PICTURE_MSG_ID", // = 14;
- "UPDATE_TEXT_ENTRY_MSG_ID", // = 15;
- "WEBCORE_INITIALIZED_MSG_ID", // = 16;
- "UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 17;
- "DID_FIRST_LAYOUT_MSG_ID", // = 18;
- "RECOMPUTE_FOCUS_MSG_ID", // = 19;
- "NOTIFY_FOCUS_SET_MSG_ID", // = 20;
- "MARK_NODE_INVALID_ID", // = 21;
- "UPDATE_CLIPBOARD", // = 22;
- "LONG_PRESS_ENTER", // = 23;
- "PREVENT_TOUCH_ID", // = 24;
- "WEBCORE_NEED_TOUCH_EVENTS", // = 25;
- "INVAL_RECT_MSG_ID" // = 26;
- };
-
- // width which view is considered to be fully zoomed out
- static final int ZOOM_OUT_WIDTH = 1024;
-
- private static final float MAX_ZOOM_RING_ANGLE = (float) (Math.PI * 2 / 3);
- private static final int ZOOM_RING_STEPS = 4;
- private static final float ZOOM_RING_ANGLE_UNIT = MAX_ZOOM_RING_ANGLE
- / ZOOM_RING_STEPS;
-
- private static final float DEFAULT_MAX_ZOOM_SCALE = 2;
- private static final float DEFAULT_MIN_ZOOM_SCALE = (float) 1/3;
- // scale limit, which can be set through viewport meta tag in the web page
- private float mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
- private float mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
-
- // initial scale in percent. 0 means using default.
- private int mInitialScale = 0;
-
- // set to true temporarily while the zoom control is being dragged
- private boolean mPreviewZoomOnly = false;
-
- // computed scale and inverse, from mZoomWidth.
- private float mActualScale = 1;
- private float mInvActualScale = 1;
- // if this is non-zero, it is used on drawing rather than mActualScale
- private float mZoomScale;
- private float mInvInitialZoomScale;
- private float mInvFinalZoomScale;
- private long mZoomStart;
- private static final int ZOOM_ANIMATION_LENGTH = 500;
-
- private boolean mUserScroll = false;
-
- private int mSnapScrollMode = SNAP_NONE;
- private static final int SNAP_NONE = 1;
- private static final int SNAP_X = 2;
- private static final int SNAP_Y = 3;
- private static final int SNAP_X_LOCK = 4;
- private static final int SNAP_Y_LOCK = 5;
- private boolean mSnapPositive;
-
- // Used to match key downs and key ups
- private boolean mGotKeyDown;
-
- /* package */ static boolean mLogEvent = true;
- private static final int EVENT_LOG_ZOOM_LEVEL_CHANGE = 70101;
- private static final int EVENT_LOG_DOUBLE_TAP_DURATION = 70102;
-
- // for event log
- private long mLastTouchUpTime = 0;
-
- /**
- * URI scheme for telephone number
- */
- public static final String SCHEME_TEL = "tel:";
- /**
- * URI scheme for email address
- */
- public static final String SCHEME_MAILTO = "mailto:";
- /**
- * URI scheme for map address
- */
- public static final String SCHEME_GEO = "geo:0,0?q=";
-
- private int mBackgroundColor = Color.WHITE;
-
- // Used to notify listeners of a new picture.
- private PictureListener mPictureListener;
- /**
- * Interface to listen for new pictures as they change.
- */
- public interface PictureListener {
- /**
- * Notify the listener that the picture has changed.
- * @param view The WebView that owns the picture.
- * @param picture The new picture.
- */
- public void onNewPicture(WebView view, Picture picture);
- }
-
- public class HitTestResult {
- /**
- * Default HitTestResult, where the target is unknown
- */
- public static final int UNKNOWN_TYPE = 0;
- /**
- * HitTestResult for hitting a HTML::a tag
- */
- public static final int ANCHOR_TYPE = 1;
- /**
- * HitTestResult for hitting a phone number
- */
- public static final int PHONE_TYPE = 2;
- /**
- * HitTestResult for hitting a map address
- */
- public static final int GEO_TYPE = 3;
- /**
- * HitTestResult for hitting an email address
- */
- public static final int EMAIL_TYPE = 4;
- /**
- * HitTestResult for hitting an HTML::img tag
- */
- public static final int IMAGE_TYPE = 5;
- /**
- * HitTestResult for hitting a HTML::a tag which contains HTML::img
- */
- public static final int IMAGE_ANCHOR_TYPE = 6;
- /**
- * HitTestResult for hitting a HTML::a tag with src=http
- */
- public static final int SRC_ANCHOR_TYPE = 7;
- /**
- * HitTestResult for hitting a HTML::a tag with src=http + HTML::img
- */
- public static final int SRC_IMAGE_ANCHOR_TYPE = 8;
- /**
- * HitTestResult for hitting an edit text area
- */
- public static final int EDIT_TEXT_TYPE = 9;
-
- private int mType;
- private String mExtra;
-
- HitTestResult() {
- mType = UNKNOWN_TYPE;
- }
-
- private void setType(int type) {
- mType = type;
- }
-
- private void setExtra(String extra) {
- mExtra = extra;
- }
-
- public int getType() {
- return mType;
- }
-
- public String getExtra() {
- return mExtra;
- }
- }
-
- private ZoomRingController mZoomRingController;
- private ImageView mZoomRingOverview;
- private Animation mZoomRingOverviewExitAnimation;
-
- // These keep track of the center point of the zoom ring. They are used to
- // determine the point around which we should zoom.
- private float mZoomCenterX;
- private float mZoomCenterY;
-
- private ZoomRingController.OnZoomListener mZoomListener =
- new ZoomRingController.OnZoomListener() {
-
- private float mClockwiseBound;
- private float mCounterClockwiseBound;
- private float mStartScale;
-
- public void onCenter(int x, int y) {
- // Don't translate when the control is invoked, hence we do nothing
- // in this callback
- }
-
- public void onBeginPan() {
- setZoomOverviewVisible(false);
- if (mLogEvent) {
- Checkin.updateStats(mContext.getContentResolver(),
- Checkin.Stats.Tag.BROWSER_ZOOM_RING_DRAG, 1, 0.0);
- }
- }
-
- public boolean onPan(int deltaX, int deltaY) {
- return pinScrollBy(deltaX, deltaY, false, 0);
- }
-
- public void onEndPan() {
- }
-
- public void onVisibilityChanged(boolean visible) {
- if (visible) {
- switchOutDrawHistory();
- if (mMaxZoomScale - 1 > ZOOM_RING_STEPS * 0.01f) {
- mClockwiseBound = (float) (2 * Math.PI - MAX_ZOOM_RING_ANGLE);
- } else {
- mClockwiseBound = (float) (2 * Math.PI);
- }
- mZoomRingController.setThumbClockwiseBound(mClockwiseBound);
- if (1 - mMinZoomScale > ZOOM_RING_STEPS * 0.01f) {
- mCounterClockwiseBound = MAX_ZOOM_RING_ANGLE;
- } else {
- mCounterClockwiseBound = 0;
- }
- mZoomRingController
- .setThumbCounterclockwiseBound(mCounterClockwiseBound);
- float angle = 0f;
- if (mActualScale > 1 && mClockwiseBound < (float) (2 * Math.PI)) {
- angle = -(float) Math.round(ZOOM_RING_STEPS
- * (mActualScale - 1) / (mMaxZoomScale - 1))
- / ZOOM_RING_STEPS;
- } else if (mActualScale < 1 && mCounterClockwiseBound > 0) {
- angle = (float) Math.round(ZOOM_RING_STEPS
- * (1 - mActualScale) / (1 - mMinZoomScale))
- / ZOOM_RING_STEPS;
- }
- mZoomRingController.setThumbAngle(angle * MAX_ZOOM_RING_ANGLE);
-
- // Show the zoom overview tab on the ring
- setZoomOverviewVisible(true);
- if (mLogEvent) {
- Checkin.updateStats(mContext.getContentResolver(),
- Checkin.Stats.Tag.BROWSER_ZOOM_RING, 1, 0.0);
- }
- }
- }
-
- public void onBeginDrag() {
- mPreviewZoomOnly = true;
- mStartScale = mActualScale;
- setZoomOverviewVisible(false);
- }
-
- public void onEndDrag() {
- mPreviewZoomOnly = false;
- if (mLogEvent) {
- EventLog.writeEvent(EVENT_LOG_ZOOM_LEVEL_CHANGE,
- (int) mStartScale * 100, (int) mActualScale * 100,
- System.currentTimeMillis());
- }
- setNewZoomScale(mActualScale, true);
- }
-
- public boolean onDragZoom(int deltaZoomLevel, int centerX,
- int centerY, float startAngle, float curAngle) {
- if (deltaZoomLevel < 0
- && Math.abs(mActualScale - mMinZoomScale) < 0.01f
- || deltaZoomLevel > 0
- && Math.abs(mActualScale - mMaxZoomScale) < 0.01f
- || deltaZoomLevel == 0) {
- return false;
- }
- mZoomCenterX = (float) centerX;
- mZoomCenterY = (float) centerY;
-
- float scale = 1.0f;
- // curAngle is [0, 2 * Math.PI)
- if (curAngle < (float) Math.PI) {
- if (curAngle >= mCounterClockwiseBound) {
- scale = mMinZoomScale;
- } else {
- scale = 1 - (float) Math.round(curAngle
- / ZOOM_RING_ANGLE_UNIT) / ZOOM_RING_STEPS
- * (1 - mMinZoomScale);
- }
- } else {
- if (curAngle <= mClockwiseBound) {
- scale = mMaxZoomScale;
- } else {
- scale = 1 + (float) Math.round(
- ((float) 2 * Math.PI - curAngle)
- / ZOOM_RING_ANGLE_UNIT) / ZOOM_RING_STEPS
- * (mMaxZoomScale - 1);
- }
- }
- zoomWithPreview(scale);
- return true;
- }
-
- public void onSimpleZoom(boolean zoomIn) {
- if (zoomIn) {
- zoomIn();
- } else {
- zoomOut();
- }
- }
-
- };
-
- /**
- * Construct a new WebView with a Context object.
- * @param context A Context object used to access application assets.
- */
- public WebView(Context context) {
- this(context, null);
- }
-
- /**
- * Construct a new WebView with layout parameters.
- * @param context A Context object used to access application assets.
- * @param attrs An AttributeSet passed to our parent.
- */
- public WebView(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.webViewStyle);
- }
-
- /**
- * Construct a new WebView with layout parameters and a default style.
- * @param context A Context object used to access application assets.
- * @param attrs An AttributeSet passed to our parent.
- * @param defStyle The default style resource ID.
- */
- public WebView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init();
-
- mCallbackProxy = new CallbackProxy(context, this);
- mWebViewCore = new WebViewCore(context, this, mCallbackProxy);
- mDatabase = WebViewDatabase.getInstance(context);
- mFocusData = new WebViewCore.FocusData();
- mFocusData.mFrame = 0;
- mFocusData.mNode = 0;
- mFocusData.mX = 0;
- mFocusData.mY = 0;
- mScroller = new Scroller(context);
- mZoomRingController = new ZoomRingController(context, this);
- mZoomRingController.setResetThumbAutomatically(false);
- mZoomRingController.setCallback(mZoomListener);
- mZoomRingController.setZoomRingTrack(
- com.android.internal.R.drawable.zoom_ring_track_absolute);
- mZoomRingController.setPannerAcceleration(160);
- mZoomRingController.setPannerStartAcceleratingDuration(700);
- createZoomRingOverviewTab();
- }
-
- private void init() {
- setWillNotDraw(false);
- setFocusable(true);
- setFocusableInTouchMode(true);
- setClickable(true);
- setLongClickable(true);
-
- final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
- mTouchSlopSquare = slop * slop;
- mMinLockSnapReverseDistance = slop;
- }
-
- private void createZoomRingOverviewTab() {
- Context context = getContext();
-
- mZoomRingOverviewExitAnimation = AnimationUtils.loadAnimation(context,
- com.android.internal.R.anim.fade_out);
-
- mZoomRingOverview = new ImageView(context);
- mZoomRingOverview.setBackgroundResource(
- com.android.internal.R.drawable.zoom_ring_overview_tab);
- mZoomRingOverview.setImageResource(com.android.internal.R.drawable.btn_zoom_page);
-
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- FrameLayout.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER);
- // TODO: magic constant that's based on the zoom ring radius + some offset
- lp.topMargin = 208;
- mZoomRingOverview.setLayoutParams(lp);
- mZoomRingOverview.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- // Hide the zoom ring
- mZoomRingController.setVisible(false);
- if (mLogEvent) {
- Checkin.updateStats(mContext.getContentResolver(),
- Checkin.Stats.Tag.BROWSER_ZOOM_OVERVIEW, 1, 0.0);
- }
- zoomScrollOut();
- }});
-
- // Measure the overview View to figure out its height
- mZoomRingOverview.forceLayout();
- mZoomRingOverview.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-
- ViewGroup container = mZoomRingController.getContainer();
- // Find the index of the zoom ring in the container
- View zoomRing = container.findViewById(mZoomRingController.getZoomRingId());
- int zoomRingIndex;
- for (zoomRingIndex = container.getChildCount() - 1; zoomRingIndex >= 0; zoomRingIndex--) {
- if (container.getChildAt(zoomRingIndex) == zoomRing) break;
- }
- // Add the overview tab below the zoom ring (so we don't steal its events)
- container.addView(mZoomRingOverview, zoomRingIndex);
- // Since we use margins to adjust the vertical placement of the tab, the widget
- // ends up getting clipped off. Ensure the container is big enough for
- // us.
- int myHeight = mZoomRingOverview.getMeasuredHeight() + lp.topMargin / 2;
- // Multiplied by 2 b/c the zoom ring needs to be centered on the screen
- container.setMinimumHeight(myHeight * 2);
- }
-
- private void setZoomOverviewVisible(boolean visible) {
- int newVisibility = visible ? View.VISIBLE : View.INVISIBLE;
- if (mZoomRingOverview.getVisibility() == newVisibility) return;
-
- if (!visible) {
- mZoomRingOverview.startAnimation(mZoomRingOverviewExitAnimation);
- }
- mZoomRingOverview.setVisibility(newVisibility);
- }
-
- /* package */ boolean onSavePassword(String schemePlusHost, String username,
- String password, final Message resumeMsg) {
- boolean rVal = false;
- if (resumeMsg == null) {
- // null resumeMsg implies saving password silently
- mDatabase.setUsernamePassword(schemePlusHost, username, password);
- } else {
- final Message remember = mPrivateHandler.obtainMessage(
- REMEMBER_PASSWORD);
- remember.getData().putString("host", schemePlusHost);
- remember.getData().putString("username", username);
- remember.getData().putString("password", password);
- remember.obj = resumeMsg;
-
- final Message neverRemember = mPrivateHandler.obtainMessage(
- NEVER_REMEMBER_PASSWORD);
- neverRemember.getData().putString("host", schemePlusHost);
- neverRemember.getData().putString("username", username);
- neverRemember.getData().putString("password", password);
- neverRemember.obj = resumeMsg;
-
- new AlertDialog.Builder(getContext())
- .setTitle(com.android.internal.R.string.save_password_label)
- .setMessage(com.android.internal.R.string.save_password_message)
- .setPositiveButton(com.android.internal.R.string.save_password_notnow,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- resumeMsg.sendToTarget();
- }
- })
- .setNeutralButton(com.android.internal.R.string.save_password_remember,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- remember.sendToTarget();
- }
- })
- .setNegativeButton(com.android.internal.R.string.save_password_never,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- neverRemember.sendToTarget();
- }
- })
- .setOnCancelListener(new OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- resumeMsg.sendToTarget();
- }
- }).show();
- // Return true so that WebViewCore will pause while the dialog is
- // up.
- rVal = true;
- }
- return rVal;
- }
-
- @Override
- public void setScrollBarStyle(int style) {
- if (style == View.SCROLLBARS_INSIDE_INSET
- || style == View.SCROLLBARS_OUTSIDE_INSET) {
- mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false;
- } else {
- mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true;
- }
- super.setScrollBarStyle(style);
- }
-
- /**
- * Specify whether the horizontal scrollbar has overlay style.
- * @param overlay TRUE if horizontal scrollbar should have overlay style.
- */
- public void setHorizontalScrollbarOverlay(boolean overlay) {
- mOverlayHorizontalScrollbar = overlay;
- }
-
- /**
- * Specify whether the vertical scrollbar has overlay style.
- * @param overlay TRUE if vertical scrollbar should have overlay style.
- */
- public void setVerticalScrollbarOverlay(boolean overlay) {
- mOverlayVerticalScrollbar = overlay;
- }
-
- /**
- * Return whether horizontal scrollbar has overlay style
- * @return TRUE if horizontal scrollbar has overlay style.
- */
- public boolean overlayHorizontalScrollbar() {
- return mOverlayHorizontalScrollbar;
- }
-
- /**
- * Return whether vertical scrollbar has overlay style
- * @return TRUE if vertical scrollbar has overlay style.
- */
- public boolean overlayVerticalScrollbar() {
- return mOverlayVerticalScrollbar;
- }
-
- /*
- * Return the width of the view where the content of WebView should render
- * to.
- */
- private int getViewWidth() {
- if (!isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) {
- return getWidth();
- } else {
- return getWidth() - getVerticalScrollbarWidth();
- }
- }
-
- /*
- * Return the height of the view where the content of WebView should render
- * to.
- */
- private int getViewHeight() {
- if (!isHorizontalScrollBarEnabled() || mOverlayHorizontalScrollbar) {
- return getHeight();
- } else {
- return getHeight() - getHorizontalScrollbarHeight();
- }
- }
-
- /**
- * @return The SSL certificate for the main top-level page or null if
- * there is no certificate (the site is not secure).
- */
- public SslCertificate getCertificate() {
- return mCertificate;
- }
-
- /**
- * Sets the SSL certificate for the main top-level page.
- */
- public void setCertificate(SslCertificate certificate) {
- // here, the certificate can be null (if the site is not secure)
- mCertificate = certificate;
- }
-
- //-------------------------------------------------------------------------
- // Methods called by activity
- //-------------------------------------------------------------------------
-
- /**
- * Save the username and password for a particular host in the WebView's
- * internal database.
- * @param host The host that required the credentials.
- * @param username The username for the given host.
- * @param password The password for the given host.
- */
- public void savePassword(String host, String username, String password) {
- mDatabase.setUsernamePassword(host, username, password);
- }
-
- /**
- * Set the HTTP authentication credentials for a given host and realm.
- *
- * @param host The host for the credentials.
- * @param realm The realm for the credentials.
- * @param username The username for the password. If it is null, it means
- * password can't be saved.
- * @param password The password
- */
- public void setHttpAuthUsernamePassword(String host, String realm,
- String username, String password) {
- mDatabase.setHttpAuthUsernamePassword(host, realm, username, password);
- }
-
- /**
- * Retrieve the HTTP authentication username and password for a given
- * host & realm pair
- *
- * @param host The host for which the credentials apply.
- * @param realm The realm for which the credentials apply.
- * @return String[] if found, String[0] is username, which can be null and
- * String[1] is password. Return null if it can't find anything.
- */
- public String[] getHttpAuthUsernamePassword(String host, String realm) {
- return mDatabase.getHttpAuthUsernamePassword(host, realm);
- }
-
- /**
- * Destroy the internal state of the WebView. This method should be called
- * after the WebView has been removed from the view system. No other
- * methods may be called on a WebView after destroy.
- */
- public void destroy() {
- clearTextEntry();
- if (mWebViewCore != null) {
- // Set the handlers to null before destroying WebViewCore so no
- // more messages will be posted.
- mCallbackProxy.setWebViewClient(null);
- mCallbackProxy.setWebChromeClient(null);
- // Tell WebViewCore to destroy itself
- WebViewCore webViewCore = mWebViewCore;
- mWebViewCore = null; // prevent using partial webViewCore
- webViewCore.destroy();
- // Remove any pending messages that might not be serviced yet.
- mPrivateHandler.removeCallbacksAndMessages(null);
- mCallbackProxy.removeCallbacksAndMessages(null);
- // Wake up the WebCore thread just in case it is waiting for a
- // javascript dialog.
- synchronized (mCallbackProxy) {
- mCallbackProxy.notify();
- }
- }
- if (mNativeClass != 0) {
- nativeDestroy();
- mNativeClass = 0;
- }
- }
-
- /**
- * Enables platform notifications of data state and proxy changes.
- */
- public static void enablePlatformNotifications() {
- Network.enablePlatformNotifications();
- }
-
- /**
- * If platform notifications are enabled, this should be called
- * from onPause() or onStop().
- */
- public static void disablePlatformNotifications() {
- Network.disablePlatformNotifications();
- }
-
- /**
- * Inform WebView of the network state. This is used to set
- * the javascript property window.navigator.isOnline and
- * generates the online/offline event as specified in HTML5, sec. 5.7.7
- * @param networkUp boolean indicating if network is available
- *
- * @hide pending API Council approval
- */
- public void setNetworkAvailable(boolean networkUp) {
- BrowserFrame.sJavaBridge.setNetworkOnLine(networkUp);
- }
-
- /**
- * Save the state of this WebView used in
- * {@link android.app.Activity#onSaveInstanceState}. Please note that this
- * method no longer stores the display data for this WebView. The previous
- * behavior could potentially leak files if {@link #restoreState} was never
- * called. See {@link #savePicture} and {@link #restorePicture} for saving
- * and restoring the display data.
- * @param outState The Bundle to store the WebView state.
- * @return The same copy of the back/forward list used to save the state. If
- * saveState fails, the returned list will be null.
- * @see #savePicture
- * @see #restorePicture
- */
- public WebBackForwardList saveState(Bundle outState) {
- if (outState == null) {
- return null;
- }
- // We grab a copy of the back/forward list because a client of WebView
- // may have invalidated the history list by calling clearHistory.
- WebBackForwardList list = copyBackForwardList();
- final int currentIndex = list.getCurrentIndex();
- final int size = list.getSize();
- // We should fail saving the state if the list is empty or the index is
- // not in a valid range.
- if (currentIndex < 0 || currentIndex >= size || size == 0) {
- return null;
- }
- outState.putInt("index", currentIndex);
- // FIXME: This should just be a byte[][] instead of ArrayList but
- // Parcel.java does not have the code to handle multi-dimensional
- // arrays.
- ArrayList<byte[]> history = new ArrayList<byte[]>(size);
- for (int i = 0; i < size; i++) {
- WebHistoryItem item = list.getItemAtIndex(i);
- byte[] data = item.getFlattenedData();
- if (data == null) {
- // It would be very odd to not have any data for a given history
- // item. And we will fail to rebuild the history list without
- // flattened data.
- return null;
- }
- history.add(data);
- }
- outState.putSerializable("history", history);
- if (mCertificate != null) {
- outState.putBundle("certificate",
- SslCertificate.saveState(mCertificate));
- }
- return list;
- }
-
- /**
- * Save the current display data to the Bundle given. Used in conjunction
- * with {@link #saveState}.
- * @param b A Bundle to store the display data.
- * @param dest The file to store the serialized picture data. Will be
- * overwritten with this WebView's picture data.
- * @return True if the picture was successfully saved.
- */
- public boolean savePicture(Bundle b, File dest) {
- if (dest == null || b == null) {
- return false;
- }
- final Picture p = capturePicture();
- try {
- final FileOutputStream out = new FileOutputStream(dest);
- p.writeToStream(out);
- out.close();
- } catch (FileNotFoundException e){
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (RuntimeException e) {
- e.printStackTrace();
- }
- if (dest.length() > 0) {
- b.putInt("scrollX", mScrollX);
- b.putInt("scrollY", mScrollY);
- b.putFloat("scale", mActualScale);
- return true;
- }
- return false;
- }
-
- /**
- * Restore the display data that was save in {@link #savePicture}. Used in
- * conjunction with {@link #restoreState}.
- * @param b A Bundle containing the saved display data.
- * @param src The file where the picture data was stored.
- * @return True if the picture was successfully restored.
- */
- public boolean restorePicture(Bundle b, File src) {
- if (src == null || b == null) {
- return false;
- }
- if (src.exists()) {
- Picture p = null;
- try {
- final FileInputStream in = new FileInputStream(src);
- p = Picture.createFromStream(in);
- in.close();
- } catch (FileNotFoundException e){
- e.printStackTrace();
- } catch (RuntimeException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (p != null) {
- int sx = b.getInt("scrollX", 0);
- int sy = b.getInt("scrollY", 0);
- float scale = b.getFloat("scale", 1.0f);
- mDrawHistory = true;
- mHistoryPicture = p;
- mScrollX = sx;
- mScrollY = sy;
- mHistoryWidth = Math.round(p.getWidth() * scale);
- mHistoryHeight = Math.round(p.getHeight() * scale);
- // as getWidth() / getHeight() of the view are not
- // available yet, set up mActualScale, so that when
- // onSizeChanged() is called, the rest will be set
- // correctly
- mActualScale = scale;
- invalidate();
- return true;
- }
- }
- return false;
- }
-
- /**
- * Restore the state of this WebView from the given map used in
- * {@link android.app.Activity#onRestoreInstanceState}. This method should
- * be called to restore the state of the WebView before using the object. If
- * it is called after the WebView has had a chance to build state (load
- * pages, create a back/forward list, etc.) there may be undesirable
- * side-effects. Please note that this method no longer restores the
- * display data for this WebView. See {@link #savePicture} and {@link
- * #restorePicture} for saving and restoring the display data.
- * @param inState The incoming Bundle of state.
- * @return The restored back/forward list or null if restoreState failed.
- * @see #savePicture
- * @see #restorePicture
- */
- public WebBackForwardList restoreState(Bundle inState) {
- WebBackForwardList returnList = null;
- if (inState == null) {
- return returnList;
- }
- if (inState.containsKey("index") && inState.containsKey("history")) {
- mCertificate = SslCertificate.restoreState(
- inState.getBundle("certificate"));
-
- final WebBackForwardList list = mCallbackProxy.getBackForwardList();
- final int index = inState.getInt("index");
- // We can't use a clone of the list because we need to modify the
- // shared copy, so synchronize instead to prevent concurrent
- // modifications.
- synchronized (list) {
- final List<byte[]> history =
- (List<byte[]>) inState.getSerializable("history");
- final int size = history.size();
- // Check the index bounds so we don't crash in native code while
- // restoring the history index.
- if (index < 0 || index >= size) {
- return null;
- }
- for (int i = 0; i < size; i++) {
- byte[] data = history.remove(0);
- if (data == null) {
- // If we somehow have null data, we cannot reconstruct
- // the item and thus our history list cannot be rebuilt.
- return null;
- }
- WebHistoryItem item = new WebHistoryItem(data);
- list.addHistoryItem(item);
- }
- // Grab the most recent copy to return to the caller.
- returnList = copyBackForwardList();
- // Update the copy to have the correct index.
- returnList.setCurrentIndex(index);
- }
- // Remove all pending messages because we are restoring previous
- // state.
- mWebViewCore.removeMessages();
- // Send a restore state message.
- mWebViewCore.sendMessage(EventHub.RESTORE_STATE, index);
- }
- return returnList;
- }
-
- /**
- * Load the given url.
- * @param url The url of the resource to load.
- */
- public void loadUrl(String url) {
- switchOutDrawHistory();
- mWebViewCore.sendMessage(EventHub.LOAD_URL, url);
- clearTextEntry();
- }
-
- /**
- * Load the given data into the WebView. This will load the data into
- * WebView using the data: scheme. Content loaded through this mechanism
- * does not have the ability to load content from the network.
- * @param data A String of data in the given encoding.
- * @param mimeType The MIMEType of the data. i.e. text/html, image/jpeg
- * @param encoding The encoding of the data. i.e. utf-8, base64
- */
- public void loadData(String data, String mimeType, String encoding) {
- loadUrl("data:" + mimeType + ";" + encoding + "," + data);
- }
-
- /**
- * Load the given data into the WebView, use the provided URL as the base
- * URL for the content. The base URL is the URL that represents the page
- * that is loaded through this interface. As such, it is used for the
- * history entry and to resolve any relative URLs. The failUrl is used if
- * browser fails to load the data provided. If it is empty or null, and the
- * load fails, then no history entry is created.
- * <p>
- * Note for post 1.0. Due to the change in the WebKit, the access to asset
- * files through "file:///android_asset/" for the sub resources is more
- * restricted. If you provide null or empty string as baseUrl, you won't be
- * able to access asset files. If the baseUrl is anything other than
- * http(s)/ftp(s)/about/javascript as scheme, you can access asset files for
- * sub resources.
- *
- * @param baseUrl Url to resolve relative paths with, if null defaults to
- * "about:blank"
- * @param data A String of data in the given encoding.
- * @param mimeType The MIMEType of the data. i.e. text/html. If null,
- * defaults to "text/html"
- * @param encoding The encoding of the data. i.e. utf-8, us-ascii
- * @param failUrl URL to use if the content fails to load or null.
- */
- public void loadDataWithBaseURL(String baseUrl, String data,
- String mimeType, String encoding, String failUrl) {
-
- if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
- loadData(data, mimeType, encoding);
- return;
- }
- switchOutDrawHistory();
- HashMap arg = new HashMap();
- arg.put("baseUrl", baseUrl);
- arg.put("data", data);
- arg.put("mimeType", mimeType);
- arg.put("encoding", encoding);
- arg.put("failUrl", failUrl);
- mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
- clearTextEntry();
- }
-
- /**
- * Stop the current load.
- */
- public void stopLoading() {
- // TODO: should we clear all the messages in the queue before sending
- // STOP_LOADING?
- switchOutDrawHistory();
- mWebViewCore.sendMessage(EventHub.STOP_LOADING);
- }
-
- /**
- * Reload the current url.
- */
- public void reload() {
- switchOutDrawHistory();
- mWebViewCore.sendMessage(EventHub.RELOAD);
- }
-
- /**
- * Return true if this WebView has a back history item.
- * @return True iff this WebView has a back history item.
- */
- public boolean canGoBack() {
- WebBackForwardList l = mCallbackProxy.getBackForwardList();
- synchronized (l) {
- if (l.getClearPending()) {
- return false;
- } else {
- return l.getCurrentIndex() > 0;
- }
- }
- }
-
- /**
- * Go back in the history of this WebView.
- */
- public void goBack() {
- goBackOrForward(-1);
- }
-
- /**
- * Return true if this WebView has a forward history item.
- * @return True iff this Webview has a forward history item.
- */
- public boolean canGoForward() {
- WebBackForwardList l = mCallbackProxy.getBackForwardList();
- synchronized (l) {
- if (l.getClearPending()) {
- return false;
- } else {
- return l.getCurrentIndex() < l.getSize() - 1;
- }
- }
- }
-
- /**
- * Go forward in the history of this WebView.
- */
- public void goForward() {
- goBackOrForward(1);
- }
-
- /**
- * Return true if the page can go back or forward the given
- * number of steps.
- * @param steps The negative or positive number of steps to move the
- * history.
- */
- public boolean canGoBackOrForward(int steps) {
- WebBackForwardList l = mCallbackProxy.getBackForwardList();
- synchronized (l) {
- if (l.getClearPending()) {
- return false;
- } else {
- int newIndex = l.getCurrentIndex() + steps;
- return newIndex >= 0 && newIndex < l.getSize();
- }
- }
- }
-
- /**
- * Go to the history item that is the number of steps away from
- * the current item. Steps is negative if backward and positive
- * if forward.
- * @param steps The number of steps to take back or forward in the back
- * forward list.
- */
- public void goBackOrForward(int steps) {
- goBackOrForward(steps, false);
- }
-
- private void goBackOrForward(int steps, boolean ignoreSnapshot) {
- // every time we go back or forward, we want to reset the
- // WebView certificate:
- // if the new site is secure, we will reload it and get a
- // new certificate set;
- // if the new site is not secure, the certificate must be
- // null, and that will be the case
- mCertificate = null;
- if (steps != 0) {
- clearTextEntry();
- mWebViewCore.sendMessage(EventHub.GO_BACK_FORWARD, steps,
- ignoreSnapshot ? 1 : 0);
- }
- }
-
- private boolean extendScroll(int y) {
- int finalY = mScroller.getFinalY();
- int newY = pinLocY(finalY + y);
- if (newY == finalY) return false;
- mScroller.setFinalY(newY);
- mScroller.extendDuration(computeDuration(0, y));
- return true;
- }
-
- /**
- * Scroll the contents of the view up by half the view size
- * @param top true to jump to the top of the page
- * @return true if the page was scrolled
- */
- public boolean pageUp(boolean top) {
- if (mNativeClass == 0) {
- return false;
- }
- nativeClearFocus(-1, -1);
- if (top) {
- // go to the top of the document
- return pinScrollTo(mScrollX, 0, true, 0);
- }
- // Page up
- int h = getHeight();
- int y;
- if (h > 2 * PAGE_SCROLL_OVERLAP) {
- y = -h + PAGE_SCROLL_OVERLAP;
- } else {
- y = -h / 2;
- }
- mUserScroll = true;
- return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
- : extendScroll(y);
- }
-
- /**
- * Scroll the contents of the view down by half the page size
- * @param bottom true to jump to bottom of page
- * @return true if the page was scrolled
- */
- public boolean pageDown(boolean bottom) {
- if (mNativeClass == 0) {
- return false;
- }
- nativeClearFocus(-1, -1);
- if (bottom) {
- return pinScrollTo(mScrollX, mContentHeight, true, 0);
- }
- // Page down.
- int h = getHeight();
- int y;
- if (h > 2 * PAGE_SCROLL_OVERLAP) {
- y = h - PAGE_SCROLL_OVERLAP;
- } else {
- y = h / 2;
- }
- mUserScroll = true;
- return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
- : extendScroll(y);
- }
-
- /**
- * Clear the view so that onDraw() will draw nothing but white background,
- * and onMeasure() will return 0 if MeasureSpec is not MeasureSpec.EXACTLY
- */
- public void clearView() {
- mContentWidth = 0;
- mContentHeight = 0;
- mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
- }
-
- /**
- * Return a new picture that captures the current display of the webview.
- * This is a copy of the display, and will be unaffected if the webview
- * later loads a different URL.
- *
- * @return a picture containing the current contents of the view. Note this
- * picture is of the entire document, and is not restricted to the
- * bounds of the view.
- */
- public Picture capturePicture() {
- if (null == mWebViewCore) return null; // check for out of memory tab
- return mWebViewCore.copyContentPicture();
- }
-
- /**
- * Return true if the browser is displaying a TextView for text input.
- */
- private boolean inEditingMode() {
- return mTextEntry != null && mTextEntry.getParent() != null
- && mTextEntry.hasFocus();
- }
-
- private void clearTextEntry() {
- if (inEditingMode()) {
- mTextEntry.remove();
- }
- }
-
- /**
- * Return the current scale of the WebView
- * @return The current scale.
- */
- public float getScale() {
- return mActualScale;
- }
-
- /**
- * Set the initial scale for the WebView. 0 means default. If
- * {@link WebSettings#getUseWideViewPort()} is true, it zooms out all the
- * way. Otherwise it starts with 100%. If initial scale is greater than 0,
- * WebView starts will this value as initial scale.
- *
- * @param scaleInPercent The initial scale in percent.
- */
- public void setInitialScale(int scaleInPercent) {
- mInitialScale = scaleInPercent;
- }
-
- /**
- * Invoke the graphical zoom picker widget for this WebView. This will
- * result in the zoom widget appearing on the screen to control the zoom
- * level of this WebView.
- */
- public void invokeZoomPicker() {
- if (!getSettings().supportZoom()) {
- Log.w(LOGTAG, "This WebView doesn't support zoom.");
- return;
- }
- clearTextEntry();
- ExtendedZoomControls zoomControls = (ExtendedZoomControls)
- getZoomControls();
- zoomControls.show(true, canZoomScrollOut());
- zoomControls.requestFocus();
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- }
-
- /**
- * Return a HitTestResult based on the current focus node. If a HTML::a tag
- * is found and the anchor has a non-javascript url, the HitTestResult type
- * is set to SRC_ANCHOR_TYPE and the url is set in the "extra" field. If the
- * anchor does not have a url or if it is a javascript url, the type will
- * be UNKNOWN_TYPE and the url has to be retrieved through
- * {@link #requestFocusNodeHref} asynchronously. If a HTML::img tag is
- * found, the HitTestResult type is set to IMAGE_TYPE and the url is set in
- * the "extra" field. A type of
- * SRC_IMAGE_ANCHOR_TYPE indicates an anchor with a url that has an image as
- * a child node. If a phone number is found, the HitTestResult type is set
- * to PHONE_TYPE and the phone number is set in the "extra" field of
- * HitTestResult. If a map address is found, the HitTestResult type is set
- * to GEO_TYPE and the address is set in the "extra" field of HitTestResult.
- * If an email address is found, the HitTestResult type is set to EMAIL_TYPE
- * and the email is set in the "extra" field of HitTestResult. Otherwise,
- * HitTestResult type is set to UNKNOWN_TYPE.
- */
- public HitTestResult getHitTestResult() {
- if (mNativeClass == 0) {
- return null;
- }
-
- HitTestResult result = new HitTestResult();
-
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (node.mIsTextField || node.mIsTextArea) {
- result.setType(HitTestResult.EDIT_TEXT_TYPE);
- } else if (node.mText != null) {
- String text = node.mText;
- if (text.startsWith(SCHEME_TEL)) {
- result.setType(HitTestResult.PHONE_TYPE);
- result.setExtra(text.substring(SCHEME_TEL.length()));
- } else if (text.startsWith(SCHEME_MAILTO)) {
- result.setType(HitTestResult.EMAIL_TYPE);
- result.setExtra(text.substring(SCHEME_MAILTO.length()));
- } else if (text.startsWith(SCHEME_GEO)) {
- result.setType(HitTestResult.GEO_TYPE);
- result.setExtra(URLDecoder.decode(text
- .substring(SCHEME_GEO.length())));
- } else if (node.mIsAnchor) {
- result.setType(HitTestResult.SRC_ANCHOR_TYPE);
- result.setExtra(text);
- }
- }
- }
- int type = result.getType();
- if (type == HitTestResult.UNKNOWN_TYPE
- || type == HitTestResult.SRC_ANCHOR_TYPE) {
- // Now check to see if it is an image.
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- String text = nativeImageURI(contentX, contentY);
- if (text != null) {
- result.setType(type == HitTestResult.UNKNOWN_TYPE ?
- HitTestResult.IMAGE_TYPE :
- HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
- result.setExtra(text);
- }
- }
- return result;
- }
-
- /**
- * Request the href of an anchor element due to getFocusNodePath returning
- * "href." If hrefMsg is null, this method returns immediately and does not
- * dispatch hrefMsg to its target.
- *
- * @param hrefMsg This message will be dispatched with the result of the
- * request as the data member with "url" as key. The result can
- * be null.
- */
- public void requestFocusNodeHref(Message hrefMsg) {
- if (hrefMsg == null || mNativeClass == 0) {
- return;
- }
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (node.mIsAnchor) {
- // NOTE: We may already have the url of the anchor stored in
- // node.mText but it may be out of date or the caller may want
- // to know about javascript urls.
- mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF,
- node.mFramePointer, node.mNodePointer, hrefMsg);
- }
- }
- }
-
- /**
- * Request the url of the image last touched by the user. msg will be sent
- * to its target with a String representing the url as its object.
- *
- * @param msg This message will be dispatched with the result of the request
- * as the data member with "url" as key. The result can be null.
- */
- public void requestImageRef(Message msg) {
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- String ref = nativeImageURI(contentX, contentY);
- Bundle data = msg.getData();
- data.putString("url", ref);
- msg.setData(data);
- msg.sendToTarget();
- }
-
- private static int pinLoc(int x, int viewMax, int docMax) {
-// Log.d(LOGTAG, "-- pinLoc " + x + " " + viewMax + " " + docMax);
- if (docMax < viewMax) { // the doc has room on the sides for "blank"
- x = -(viewMax - docMax) >> 1;
-// Log.d(LOGTAG, "--- center " + x);
- } else if (x < 0) {
- x = 0;
-// Log.d(LOGTAG, "--- zero");
- } else if (x + viewMax > docMax) {
- x = docMax - viewMax;
-// Log.d(LOGTAG, "--- pin " + x);
- }
- return x;
- }
-
- // Expects x in view coordinates
- private int pinLocX(int x) {
- return pinLoc(x, getViewWidth(), computeHorizontalScrollRange());
- }
-
- // Expects y in view coordinates
- private int pinLocY(int y) {
- return pinLoc(y, getViewHeight(), computeVerticalScrollRange());
- }
-
- /*package*/ int viewToContent(int x) {
- return Math.round(x * mInvActualScale);
- }
-
- private int contentToView(int x) {
- return Math.round(x * mActualScale);
- }
-
- // Called by JNI to invalidate the View, given rectangle coordinates in
- // content space
- private void viewInvalidate(int l, int t, int r, int b) {
- invalidate(contentToView(l), contentToView(t), contentToView(r),
- contentToView(b));
- }
-
- // Called by JNI to invalidate the View after a delay, given rectangle
- // coordinates in content space
- private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
- postInvalidateDelayed(delay, contentToView(l), contentToView(t),
- contentToView(r), contentToView(b));
- }
-
- private Rect contentToView(Rect x) {
- return new Rect(contentToView(x.left), contentToView(x.top)
- , contentToView(x.right), contentToView(x.bottom));
- }
-
- /* call from webcoreview.draw(), so we're still executing in the UI thread
- */
- private void recordNewContentSize(int w, int h, boolean updateLayout) {
-
- // premature data from webkit, ignore
- if ((w | h) == 0) {
- return;
- }
-
- // don't abort a scroll animation if we didn't change anything
- if (mContentWidth != w || mContentHeight != h) {
- // record new dimensions
- mContentWidth = w;
- mContentHeight = h;
- // If history Picture is drawn, don't update scroll. They will be
- // updated when we get out of that mode.
- if (!mDrawHistory) {
- // repin our scroll, taking into account the new content size
- int oldX = mScrollX;
- int oldY = mScrollY;
- mScrollX = pinLocX(mScrollX);
- mScrollY = pinLocY(mScrollY);
- // android.util.Log.d("skia", "recordNewContentSize -
- // abortAnimation");
- mScroller.abortAnimation(); // just in case
- if (oldX != mScrollX || oldY != mScrollY) {
- sendOurVisibleRect();
- }
- }
- }
- contentSizeChanged(updateLayout);
- }
-
- private void setNewZoomScale(float scale, boolean force) {
- if (scale < mMinZoomScale) {
- scale = mMinZoomScale;
- } else if (scale > mMaxZoomScale) {
- scale = mMaxZoomScale;
- }
- if (scale != mActualScale || force) {
- if (mDrawHistory) {
- // If history Picture is drawn, don't update scroll. They will
- // be updated when we get out of that mode.
- if (scale != mActualScale && !mPreviewZoomOnly) {
- mCallbackProxy.onScaleChanged(mActualScale, scale);
- }
- mActualScale = scale;
- mInvActualScale = 1 / scale;
- if (!mPreviewZoomOnly) {
- sendViewSizeZoom();
- }
- } else {
- // update our scroll so we don't appear to jump
- // i.e. keep the center of the doc in the center of the view
-
- int oldX = mScrollX;
- int oldY = mScrollY;
- float ratio = scale * mInvActualScale; // old inverse
- float sx = ratio * oldX + (ratio - 1) * mZoomCenterX;
- float sy = ratio * oldY + (ratio - 1) * mZoomCenterY;
-
- // now update our new scale and inverse
- if (scale != mActualScale && !mPreviewZoomOnly) {
- mCallbackProxy.onScaleChanged(mActualScale, scale);
- }
- mActualScale = scale;
- mInvActualScale = 1 / scale;
-
- // as we don't have animation for scaling, don't do animation
- // for scrolling, as it causes weird intermediate state
- // pinScrollTo(Math.round(sx), Math.round(sy));
- mScrollX = pinLocX(Math.round(sx));
- mScrollY = pinLocY(Math.round(sy));
-
- if (!mPreviewZoomOnly) {
- sendViewSizeZoom();
- sendOurVisibleRect();
- }
- }
- }
- }
-
- // Used to avoid sending many visible rect messages.
- private Rect mLastVisibleRectSent;
- private Rect mLastGlobalRect;
-
- private Rect sendOurVisibleRect() {
- Rect rect = new Rect();
- calcOurContentVisibleRect(rect);
- if (mFindIsUp) {
- rect.bottom -= viewToContent(FIND_HEIGHT);
- }
- // Rect.equals() checks for null input.
- if (!rect.equals(mLastVisibleRectSent)) {
- mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
- rect.left, rect.top);
- mLastVisibleRectSent = rect;
- }
- Rect globalRect = new Rect();
- if (getGlobalVisibleRect(globalRect)
- && !globalRect.equals(mLastGlobalRect)) {
- // TODO: the global offset is only used by windowRect()
- // in ChromeClientAndroid ; other clients such as touch
- // and mouse events could return view + screen relative points.
- mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, globalRect);
- mLastGlobalRect = globalRect;
- }
- return rect;
- }
-
- // Sets r to be the visible rectangle of our webview in view coordinates
- private void calcOurVisibleRect(Rect r) {
- Point p = new Point();
- getGlobalVisibleRect(r, p);
- r.offset(-p.x, -p.y);
- }
-
- // Sets r to be our visible rectangle in content coordinates
- private void calcOurContentVisibleRect(Rect r) {
- calcOurVisibleRect(r);
- r.left = viewToContent(r.left);
- r.top = viewToContent(r.top);
- r.right = viewToContent(r.right);
- r.bottom = viewToContent(r.bottom);
- }
-
- /**
- * Compute unzoomed width and height, and if they differ from the last
- * values we sent, send them to webkit (to be used has new viewport)
- *
- * @return true if new values were sent
- */
- private boolean sendViewSizeZoom() {
- int viewWidth = getViewWidth();
- int newWidth = Math.round(viewWidth * mInvActualScale);
- int newHeight = Math.round(getViewHeight() * mInvActualScale);
- /*
- * Because the native side may have already done a layout before the
- * View system was able to measure us, we have to send a height of 0 to
- * remove excess whitespace when we grow our width. This will trigger a
- * layout and a change in content size. This content size change will
- * mean that contentSizeChanged will either call this method directly or
- * indirectly from onSizeChanged.
- */
- if (newWidth > mLastWidthSent && mWrapContent) {
- newHeight = 0;
- }
- // Avoid sending another message if the dimensions have not changed.
- if (newWidth != mLastWidthSent || newHeight != mLastHeightSent) {
- mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED,
- newWidth, newHeight, new Integer(viewWidth));
- mLastWidthSent = newWidth;
- mLastHeightSent = newHeight;
- return true;
- }
- return false;
- }
-
- @Override
- protected int computeHorizontalScrollRange() {
- if (mDrawHistory) {
- return mHistoryWidth;
- } else {
- return contentToView(mContentWidth);
- }
- }
-
- // Make sure this stays in sync with the actual height of the FindDialog.
- private static final int FIND_HEIGHT = 79;
-
- @Override
- protected int computeVerticalScrollRange() {
- if (mDrawHistory) {
- return mHistoryHeight;
- } else {
- int height = contentToView(mContentHeight);
- if (mFindIsUp) {
- height += FIND_HEIGHT;
- }
- return height;
- }
- }
-
- /**
- * Get the url for the current page. This is not always the same as the url
- * passed to WebViewClient.onPageStarted because although the load for
- * that url has begun, the current page may not have changed.
- * @return The url for the current page.
- */
- public String getUrl() {
- WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
- return h != null ? h.getUrl() : null;
- }
-
- /**
- * Get the original url for the current page. This is not always the same
- * as the url passed to WebViewClient.onPageStarted because although the
- * load for that url has begun, the current page may not have changed.
- * Also, there may have been redirects resulting in a different url to that
- * originally requested.
- * @return The url that was originally requested for the current page.
- *
- * @hide pending API Council approval
- */
- public String getOriginalUrl() {
- WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
- return h != null ? h.getOriginalUrl() : null;
- }
-
- /**
- * Get the title for the current page. This is the title of the current page
- * until WebViewClient.onReceivedTitle is called.
- * @return The title for the current page.
- */
- public String getTitle() {
- WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
- return h != null ? h.getTitle() : null;
- }
-
- /**
- * Get the favicon for the current page. This is the favicon of the current
- * page until WebViewClient.onReceivedIcon is called.
- * @return The favicon for the current page.
- */
- public Bitmap getFavicon() {
- WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
- return h != null ? h.getFavicon() : null;
- }
-
- /**
- * Get the progress for the current page.
- * @return The progress for the current page between 0 and 100.
- */
- public int getProgress() {
- return mCallbackProxy.getProgress();
- }
-
- /**
- * @return the height of the HTML content.
- */
- public int getContentHeight() {
- return mContentHeight;
- }
-
- /**
- * Pause all layout, parsing, and javascript timers. This can be useful if
- * the WebView is not visible or the application has been paused.
- */
- public void pauseTimers() {
- mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
- }
-
- /**
- * Resume all layout, parsing, and javascript timers. This will resume
- * dispatching all timers.
- */
- public void resumeTimers() {
- mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
- }
-
- /**
- * Clear the resource cache. This will cause resources to be re-downloaded
- * if accessed again.
- * <p>
- * Note: this really needs to be a static method as it clears cache for all
- * WebView. But we need mWebViewCore to send message to WebCore thread, so
- * we can't make this static.
- */
- public void clearCache(boolean includeDiskFiles) {
- mWebViewCore.sendMessage(EventHub.CLEAR_CACHE,
- includeDiskFiles ? 1 : 0, 0);
- }
-
- /**
- * Make sure that clearing the form data removes the adapter from the
- * currently focused textfield if there is one.
- */
- public void clearFormData() {
- if (inEditingMode()) {
- AutoCompleteAdapter adapter = null;
- mTextEntry.setAdapterCustom(adapter);
- }
- }
-
- /**
- * Tell the WebView to clear its internal back/forward list.
- */
- public void clearHistory() {
- mCallbackProxy.getBackForwardList().setClearPending();
- mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY);
- }
-
- /**
- * Clear the SSL preferences table stored in response to proceeding with SSL
- * certificate errors.
- */
- public void clearSslPreferences() {
- mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE);
- }
-
- /**
- * Return the WebBackForwardList for this WebView. This contains the
- * back/forward list for use in querying each item in the history stack.
- * This is a copy of the private WebBackForwardList so it contains only a
- * snapshot of the current state. Multiple calls to this method may return
- * different objects. The object returned from this method will not be
- * updated to reflect any new state.
- */
- public WebBackForwardList copyBackForwardList() {
- return mCallbackProxy.getBackForwardList().clone();
- }
-
- /*
- * Highlight and scroll to the next occurance of String in findAll.
- * Wraps the page infinitely, and scrolls. Must be called after
- * calling findAll.
- *
- * @param forward Direction to search.
- */
- public void findNext(boolean forward) {
- nativeFindNext(forward);
- }
-
- /*
- * Find all instances of find on the page and highlight them.
- * @param find String to find.
- * @return int The number of occurances of the String "find"
- * that were found.
- */
- public int findAll(String find) {
- mFindIsUp = true;
- int result = nativeFindAll(find.toLowerCase(), find.toUpperCase());
- invalidate();
- return result;
- }
-
- // Used to know whether the find dialog is open. Affects whether
- // or not we draw the highlights for matches.
- private boolean mFindIsUp;
-
- private native int nativeFindAll(String findLower, String findUpper);
- private native void nativeFindNext(boolean forward);
-
- /**
- * Return the first substring consisting of the address of a physical
- * location. Currently, only addresses in the United States are detected,
- * and consist of:
- * - a house number
- * - a street name
- * - a street type (Road, Circle, etc), either spelled out or abbreviated
- * - a city name
- * - a state or territory, either spelled out or two-letter abbr.
- * - an optional 5 digit or 9 digit zip code.
- *
- * All names must be correctly capitalized, and the zip code, if present,
- * must be valid for the state. The street type must be a standard USPS
- * spelling or abbreviation. The state or territory must also be spelled
- * or abbreviated using USPS standards. The house number may not exceed
- * five digits.
- * @param addr The string to search for addresses.
- *
- * @return the address, or if no address is found, return null.
- */
- public static String findAddress(String addr) {
- return WebViewCore.nativeFindAddress(addr);
- }
-
- /*
- * Clear the highlighting surrounding text matches created by findAll.
- */
- public void clearMatches() {
- mFindIsUp = false;
- nativeSetFindIsDown();
- // Now that the dialog has been removed, ensure that we scroll to a
- // location that is not beyond the end of the page.
- pinScrollTo(mScrollX, mScrollY, false, 0);
- invalidate();
- }
-
- /**
- * Query the document to see if it contains any image references. The
- * message object will be dispatched with arg1 being set to 1 if images
- * were found and 0 if the document does not reference any images.
- * @param response The message that will be dispatched with the result.
- */
- public void documentHasImages(Message response) {
- if (response == null) {
- return;
- }
- mWebViewCore.sendMessage(EventHub.DOC_HAS_IMAGES, response);
- }
-
- @Override
- public void computeScroll() {
- if (mScroller.computeScrollOffset()) {
- int oldX = mScrollX;
- int oldY = mScrollY;
- mScrollX = mScroller.getCurrX();
- mScrollY = mScroller.getCurrY();
- postInvalidate(); // So we draw again
- if (oldX != mScrollX || oldY != mScrollY) {
- // as onScrollChanged() is not called, sendOurVisibleRect()
- // needs to be call explicitly
- sendOurVisibleRect();
- }
- } else {
- super.computeScroll();
- }
- }
-
- private static int computeDuration(int dx, int dy) {
- int distance = Math.max(Math.abs(dx), Math.abs(dy));
- int duration = distance * 1000 / STD_SPEED;
- return Math.min(duration, MAX_DURATION);
- }
-
- // helper to pin the scrollBy parameters (already in view coordinates)
- // returns true if the scroll was changed
- private boolean pinScrollBy(int dx, int dy, boolean animate, int animationDuration) {
- return pinScrollTo(mScrollX + dx, mScrollY + dy, animate, animationDuration);
- }
-
- // helper to pin the scrollTo parameters (already in view coordinates)
- // returns true if the scroll was changed
- private boolean pinScrollTo(int x, int y, boolean animate, int animationDuration) {
- x = pinLocX(x);
- y = pinLocY(y);
- int dx = x - mScrollX;
- int dy = y - mScrollY;
-
- if ((dx | dy) == 0) {
- return false;
- }
-
- if (true && animate) {
- // Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
-
- mScroller.startScroll(mScrollX, mScrollY, dx, dy,
- animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
- invalidate();
- } else {
- mScroller.abortAnimation(); // just in case
- scrollTo(x, y);
- }
- return true;
- }
-
- // Scale from content to view coordinates, and pin.
- // Also called by jni webview.cpp
- private void setContentScrollBy(int cx, int cy, boolean animate) {
- if (mDrawHistory) {
- // disallow WebView to change the scroll position as History Picture
- // is used in the view system.
- // TODO: as we switchOutDrawHistory when trackball or navigation
- // keys are hit, this should be safe. Right?
- return;
- }
- cx = contentToView(cx);
- cy = contentToView(cy);
- if (mHeightCanMeasure) {
- // move our visible rect according to scroll request
- if (cy != 0) {
- Rect tempRect = new Rect();
- calcOurVisibleRect(tempRect);
- tempRect.offset(cx, cy);
- requestRectangleOnScreen(tempRect);
- }
- // FIXME: We scroll horizontally no matter what because currently
- // ScrollView and ListView will not scroll horizontally.
- // FIXME: Why do we only scroll horizontally if there is no
- // vertical scroll?
-// Log.d(LOGTAG, "setContentScrollBy cy=" + cy);
- if (cy == 0 && cx != 0) {
- pinScrollBy(cx, 0, animate, 0);
- }
- } else {
- pinScrollBy(cx, cy, animate, 0);
- }
- }
-
- // scale from content to view coordinates, and pin
- // return true if pin caused the final x/y different than the request cx/cy;
- // return false if the view scroll to the exact position as it is requested.
- private boolean setContentScrollTo(int cx, int cy) {
- if (mDrawHistory) {
- // disallow WebView to change the scroll position as History Picture
- // is used in the view system.
- // One known case where this is called is that WebCore tries to
- // restore the scroll position. As history Picture already uses the
- // saved scroll position, it is ok to skip this.
- return false;
- }
- int vx = contentToView(cx);
- int vy = contentToView(cy);
-// Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
-// vx + " " + vy + "]");
- pinScrollTo(vx, vy, false, 0);
- if (mScrollX != vx || mScrollY != vy) {
- return true;
- } else {
- return false;
- }
- }
-
- // scale from content to view coordinates, and pin
- private void spawnContentScrollTo(int cx, int cy) {
- if (mDrawHistory) {
- // disallow WebView to change the scroll position as History Picture
- // is used in the view system.
- return;
- }
- int vx = contentToView(cx);
- int vy = contentToView(cy);
- pinScrollTo(vx, vy, true, 0);
- }
-
- /**
- * These are from webkit, and are in content coordinate system (unzoomed)
- */
- private void contentSizeChanged(boolean updateLayout) {
- // suppress 0,0 since we usually see real dimensions soon after
- // this avoids drawing the prev content in a funny place. If we find a
- // way to consolidate these notifications, this check may become
- // obsolete
- if ((mContentWidth | mContentHeight) == 0) {
- return;
- }
-
- if (mHeightCanMeasure) {
- if (getMeasuredHeight() != contentToView(mContentHeight)
- && updateLayout) {
- requestLayout();
- }
- } else if (mWidthCanMeasure) {
- if (getMeasuredWidth() != contentToView(mContentWidth)
- && updateLayout) {
- requestLayout();
- }
- } else {
- // If we don't request a layout, try to send our view size to the
- // native side to ensure that WebCore has the correct dimensions.
- sendViewSizeZoom();
- }
- }
-
- /**
- * Set the WebViewClient that will receive various notifications and
- * requests. This will replace the current handler.
- * @param client An implementation of WebViewClient.
- */
- public void setWebViewClient(WebViewClient client) {
- mCallbackProxy.setWebViewClient(client);
- }
-
- /**
- * Register the interface to be used when content can not be handled by
- * the rendering engine, and should be downloaded instead. This will replace
- * the current handler.
- * @param listener An implementation of DownloadListener.
- */
- public void setDownloadListener(DownloadListener listener) {
- mCallbackProxy.setDownloadListener(listener);
- }
-
- /**
- * Set the chrome handler. This is an implementation of WebChromeClient for
- * use in handling Javascript dialogs, favicons, titles, and the progress.
- * This will replace the current handler.
- * @param client An implementation of WebChromeClient.
- */
- public void setWebChromeClient(WebChromeClient client) {
- mCallbackProxy.setWebChromeClient(client);
- }
-
- /**
- * Set the Picture listener. This is an interface used to receive
- * notifications of a new Picture.
- * @param listener An implementation of WebView.PictureListener.
- */
- public void setPictureListener(PictureListener listener) {
- mPictureListener = listener;
- }
-
- /**
- * {@hide}
- */
- /* FIXME: Debug only! Remove for SDK! */
- public void externalRepresentation(Message callback) {
- mWebViewCore.sendMessage(EventHub.REQUEST_EXT_REPRESENTATION, callback);
- }
-
- /**
- * {@hide}
- */
- /* FIXME: Debug only! Remove for SDK! */
- public void documentAsText(Message callback) {
- mWebViewCore.sendMessage(EventHub.REQUEST_DOC_AS_TEXT, callback);
- }
-
- /**
- * Use this function to bind an object to Javascript so that the
- * methods can be accessed from Javascript.
- * IMPORTANT, the object that is bound runs in another thread and
- * not in the thread that it was constructed in.
- * @param obj The class instance to bind to Javascript
- * @param interfaceName The name to used to expose the class in Javascript
- */
- public void addJavascriptInterface(Object obj, String interfaceName) {
- // Use Hashmap rather than Bundle as Bundles can't cope with Objects
- HashMap arg = new HashMap();
- arg.put("object", obj);
- arg.put("interfaceName", interfaceName);
- mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
- }
-
- /**
- * Return the WebSettings object used to control the settings for this
- * WebView.
- * @return A WebSettings object that can be used to control this WebView's
- * settings.
- */
- public WebSettings getSettings() {
- return mWebViewCore.getSettings();
- }
-
- /**
- * Return the list of currently loaded plugins.
- * @return The list of currently loaded plugins.
- */
- public static synchronized PluginList getPluginList() {
- if (sPluginList == null) {
- sPluginList = new PluginList();
- }
- return sPluginList;
- }
-
- /**
- * Signal the WebCore thread to refresh its list of plugins. Use
- * this if the directory contents of one of the plugin directories
- * has been modified and needs its changes reflecting. May cause
- * plugin load and/or unload.
- * @param reloadOpenPages Set to true to reload all open pages.
- */
- public void refreshPlugins(boolean reloadOpenPages) {
- if (mWebViewCore != null) {
- mWebViewCore.sendMessage(EventHub.REFRESH_PLUGINS, reloadOpenPages);
- }
- }
-
- //-------------------------------------------------------------------------
- // Override View methods
- //-------------------------------------------------------------------------
-
- @Override
- protected void finalize() throws Throwable {
- destroy();
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- // if mNativeClass is 0, the WebView has been destroyed. Do nothing.
- if (mNativeClass == 0) {
- return;
- }
- if (mWebViewCore.mEndScaleZoom) {
- mWebViewCore.mEndScaleZoom = false;
- if (mTouchMode >= FIRST_SCROLL_ZOOM
- && mTouchMode <= LAST_SCROLL_ZOOM) {
- setHorizontalScrollBarEnabled(true);
- setVerticalScrollBarEnabled(true);
- mTouchMode = TOUCH_DONE_MODE;
- }
- }
- int sc = canvas.save();
- if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
- scrollZoomDraw(canvas);
- } else {
- nativeRecomputeFocus();
- // Update the buttons in the picture, so when we draw the picture
- // to the screen, they are in the correct state.
- // Tell the native side if user is a) touching the screen,
- // b) pressing the trackball down, or c) pressing the enter key
- // If the focus is a button, we need to draw it in the pressed
- // state.
- // If mNativeClass is 0, we should not reach here, so we do not
- // need to check it again.
- nativeRecordButtons(hasFocus() && hasWindowFocus(),
- mTouchMode == TOUCH_SHORTPRESS_START_MODE
- || mTrackballDown || mGotEnterDown, false);
- drawCoreAndFocusRing(canvas, mBackgroundColor, mDrawFocusRing);
- }
- canvas.restoreToCount(sc);
-
- if (AUTO_REDRAW_HACK && mAutoRedraw) {
- invalidate();
- }
- }
-
- @Override
- public void setLayoutParams(ViewGroup.LayoutParams params) {
- if (params.height == LayoutParams.WRAP_CONTENT) {
- mWrapContent = true;
- }
- super.setLayoutParams(params);
- }
-
- @Override
- public boolean performLongClick() {
- if (inEditingMode()) {
- return mTextEntry.performLongClick();
- } else {
- return super.performLongClick();
- }
- }
-
- private void drawCoreAndFocusRing(Canvas canvas, int color,
- boolean drawFocus) {
- if (mDrawHistory) {
- canvas.scale(mActualScale, mActualScale);
- canvas.drawPicture(mHistoryPicture);
- return;
- }
-
- boolean animateZoom = mZoomScale != 0;
- boolean animateScroll = !mScroller.isFinished()
- || mVelocityTracker != null;
- if (animateZoom) {
- float zoomScale;
- int interval = (int) (SystemClock.uptimeMillis() - mZoomStart);
- if (interval < ZOOM_ANIMATION_LENGTH) {
- float ratio = (float) interval / ZOOM_ANIMATION_LENGTH;
- zoomScale = 1.0f / (mInvInitialZoomScale
- + (mInvFinalZoomScale - mInvInitialZoomScale) * ratio);
- invalidate();
- } else {
- zoomScale = mZoomScale;
- // set mZoomScale to be 0 as we have done animation
- mZoomScale = 0;
- }
- float scale = (mActualScale - zoomScale) * mInvActualScale;
- float tx = scale * (mZoomCenterX + mScrollX);
- float ty = scale * (mZoomCenterY + mScrollY);
-
- // this block pins the translate to "legal" bounds. This makes the
- // animation a bit non-obvious, but it means we won't pop when the
- // "real" zoom takes effect
- if (true) {
- // canvas.translate(mScrollX, mScrollY);
- tx -= mScrollX;
- ty -= mScrollY;
- tx = -pinLoc(-Math.round(tx), getViewWidth(), Math
- .round(mContentWidth * zoomScale));
- ty = -pinLoc(-Math.round(ty), getViewHeight(), Math
- .round(mContentHeight * zoomScale));
- tx += mScrollX;
- ty += mScrollY;
- }
- canvas.translate(tx, ty);
- canvas.scale(zoomScale, zoomScale);
- } else {
- canvas.scale(mActualScale, mActualScale);
- }
-
- mWebViewCore.drawContentPicture(canvas, color, animateZoom,
- animateScroll);
-
- if (mNativeClass == 0) return;
- if (mShiftIsPressed) {
- if (mTouchSelection) {
- nativeDrawSelectionRegion(canvas);
- } else {
- nativeDrawSelection(canvas, mSelectX, mSelectY,
- mExtendSelection);
- }
- } else if (drawFocus) {
- if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
- mTouchMode = TOUCH_SHORTPRESS_MODE;
- HitTestResult hitTest = getHitTestResult();
- if (hitTest != null &&
- hitTest.mType != HitTestResult.UNKNOWN_TYPE) {
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(SWITCH_TO_LONGPRESS),
- LONG_PRESS_TIMEOUT);
- }
- }
- nativeDrawFocusRing(canvas);
- }
- // When the FindDialog is up, only draw the matches if we are not in
- // the process of scrolling them into view.
- if (mFindIsUp && !animateScroll) {
- nativeDrawMatches(canvas);
- }
- }
-
- private native void nativeDrawMatches(Canvas canvas);
-
- private float scrollZoomGridScale(float invScale) {
- float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID)
- / (float) SCROLL_ZOOM_GRID;
- return 1.0f / griddedInvScale;
- }
-
- private float scrollZoomX(float scale) {
- int width = getViewWidth();
- float maxScrollZoomX = mContentWidth * scale - width;
- int maxX = mContentWidth - width;
- return -(maxScrollZoomX > 0 ? mZoomScrollX * maxScrollZoomX / maxX
- : maxScrollZoomX / 2);
- }
-
- private float scrollZoomY(float scale) {
- int height = getViewHeight();
- float maxScrollZoomY = mContentHeight * scale - height;
- int maxY = mContentHeight - height;
- return -(maxScrollZoomY > 0 ? mZoomScrollY * maxScrollZoomY / maxY
- : maxScrollZoomY / 2);
- }
-
- private void drawMagnifyFrame(Canvas canvas, Rect frame, Paint paint) {
- final float ADORNMENT_LEN = 16.0f;
- float width = frame.width();
- float height = frame.height();
- Path path = new Path();
- path.moveTo(-ADORNMENT_LEN, -ADORNMENT_LEN);
- path.lineTo(0, 0);
- path.lineTo(width, 0);
- path.lineTo(width + ADORNMENT_LEN, -ADORNMENT_LEN);
- path.moveTo(-ADORNMENT_LEN, height + ADORNMENT_LEN);
- path.lineTo(0, height);
- path.lineTo(width, height);
- path.lineTo(width + ADORNMENT_LEN, height + ADORNMENT_LEN);
- path.moveTo(0, 0);
- path.lineTo(0, height);
- path.moveTo(width, 0);
- path.lineTo(width, height);
- path.offset(frame.left, frame.top);
- canvas.drawPath(path, paint);
- }
-
- // Returns frame surrounding magified portion of screen while
- // scroll-zoom is enabled. The frame is also used to center the
- // zoom-in zoom-out points at the start and end of the animation.
- private Rect scrollZoomFrame(int width, int height, float halfScale) {
- Rect scrollFrame = new Rect();
- scrollFrame.set(mZoomScrollX, mZoomScrollY,
- mZoomScrollX + width, mZoomScrollY + height);
- if (mContentWidth * mZoomScrollLimit < width) {
- float scale = zoomFrameScaleX(width, halfScale, 1.0f);
- float offsetX = (width * scale - width) * 0.5f;
- scrollFrame.left -= offsetX;
- scrollFrame.right += offsetX;
- }
- if (mContentHeight * mZoomScrollLimit < height) {
- float scale = zoomFrameScaleY(height, halfScale, 1.0f);
- float offsetY = (height * scale - height) * 0.5f;
- scrollFrame.top -= offsetY;
- scrollFrame.bottom += offsetY;
- }
- return scrollFrame;
- }
-
- private float zoomFrameScaleX(int width, float halfScale, float noScale) {
- // mContentWidth > width > mContentWidth * mZoomScrollLimit
- if (mContentWidth <= width) {
- return halfScale;
- }
- float part = (width - mContentWidth * mZoomScrollLimit)
- / (width * (1 - mZoomScrollLimit));
- return halfScale * part + noScale * (1.0f - part);
- }
-
- private float zoomFrameScaleY(int height, float halfScale, float noScale) {
- if (mContentHeight <= height) {
- return halfScale;
- }
- float part = (height - mContentHeight * mZoomScrollLimit)
- / (height * (1 - mZoomScrollLimit));
- return halfScale * part + noScale * (1.0f - part);
- }
-
- private float scrollZoomMagScale(float invScale) {
- return (invScale * 2 + mInvActualScale) / 3;
- }
-
- private void scrollZoomDraw(Canvas canvas) {
- float invScale = mZoomScrollInvLimit;
- int elapsed = 0;
- if (mTouchMode != SCROLL_ZOOM_OUT) {
- elapsed = (int) Math.min(System.currentTimeMillis()
- - mZoomScrollStart, SCROLL_ZOOM_DURATION);
- float transitionScale = (mZoomScrollInvLimit - mInvActualScale)
- * elapsed / SCROLL_ZOOM_DURATION;
- if (mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
- invScale = mInvActualScale + transitionScale;
- } else { /* if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN) */
- invScale = mZoomScrollInvLimit - transitionScale;
- }
- }
- float scale = scrollZoomGridScale(invScale);
- invScale = 1.0f / scale;
- int width = getViewWidth();
- int height = getViewHeight();
- float halfScale = scrollZoomMagScale(invScale);
- Rect scrollFrame = scrollZoomFrame(width, height, halfScale);
- if (elapsed == SCROLL_ZOOM_DURATION) {
- if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN) {
- setHorizontalScrollBarEnabled(true);
- setVerticalScrollBarEnabled(true);
- updateTextEntry();
- scrollTo((int) (scrollFrame.centerX() * mActualScale)
- - (width >> 1), (int) (scrollFrame.centerY()
- * mActualScale) - (height >> 1));
- mTouchMode = TOUCH_DONE_MODE;
- } else {
- mTouchMode = SCROLL_ZOOM_OUT;
- }
- }
- float newX = scrollZoomX(scale);
- float newY = scrollZoomY(scale);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "scrollZoomDraw scale=" + scale + " + (" + newX
- + ", " + newY + ") mZoomScroll=(" + mZoomScrollX + ", "
- + mZoomScrollY + ")" + " invScale=" + invScale + " scale="
- + scale);
- }
- canvas.translate(newX, newY);
- canvas.scale(scale, scale);
- boolean animating = mTouchMode != SCROLL_ZOOM_OUT;
- if (mDrawHistory) {
- int sc = canvas.save(Canvas.CLIP_SAVE_FLAG);
- Rect clip = new Rect(0, 0, mHistoryPicture.getWidth(),
- mHistoryPicture.getHeight());
- canvas.clipRect(clip, Region.Op.DIFFERENCE);
- canvas.drawColor(mBackgroundColor);
- canvas.restoreToCount(sc);
- canvas.drawPicture(mHistoryPicture);
- } else {
- mWebViewCore.drawContentPicture(canvas, mBackgroundColor,
- animating, true);
- }
- if (mTouchMode == TOUCH_DONE_MODE) {
- return;
- }
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setStyle(Paint.Style.STROKE);
- paint.setStrokeWidth(30.0f);
- paint.setARGB(0x50, 0, 0, 0);
- int maxX = mContentWidth - width;
- int maxY = mContentHeight - height;
- if (true) { // experiment: draw hint to place finger off magnify area
- drawMagnifyFrame(canvas, scrollFrame, paint);
- } else {
- canvas.drawRect(scrollFrame, paint);
- }
- int sc = canvas.save();
- canvas.clipRect(scrollFrame);
- float halfX = (float) mZoomScrollX / maxX;
- if (mContentWidth * mZoomScrollLimit < width) {
- halfX = zoomFrameScaleX(width, 0.5f, halfX);
- }
- float halfY = (float) mZoomScrollY / maxY;
- if (mContentHeight * mZoomScrollLimit < height) {
- halfY = zoomFrameScaleY(height, 0.5f, halfY);
- }
- canvas.scale(halfScale, halfScale, mZoomScrollX + width * halfX
- , mZoomScrollY + height * halfY);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=("
- + width + ", " + height + ") half=(" + halfX + ", "
- + halfY + ")");
- }
- if (mDrawHistory) {
- canvas.drawPicture(mHistoryPicture);
- } else {
- mWebViewCore.drawContentPicture(canvas, mBackgroundColor,
- animating, false);
- }
- canvas.restoreToCount(sc);
- if (mTouchMode != SCROLL_ZOOM_OUT) {
- invalidate();
- }
- }
-
- private void zoomScrollTap(float x, float y) {
- float scale = scrollZoomGridScale(mZoomScrollInvLimit);
- float left = scrollZoomX(scale);
- float top = scrollZoomY(scale);
- int width = getViewWidth();
- int height = getViewHeight();
- x -= width * scale / 2;
- y -= height * scale / 2;
- mZoomScrollX = Math.min(mContentWidth - width
- , Math.max(0, (int) ((x - left) / scale)));
- mZoomScrollY = Math.min(mContentHeight - height
- , Math.max(0, (int) ((y - top) / scale)));
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "zoomScrollTap scale=" + scale + " + (" + left
- + ", " + top + ") mZoomScroll=(" + mZoomScrollX + ", "
- + mZoomScrollY + ")" + " x=" + x + " y=" + y);
- }
- }
-
- private boolean canZoomScrollOut() {
- if (mContentWidth == 0 || mContentHeight == 0) {
- return false;
- }
- int width = getViewWidth();
- int height = getViewHeight();
- float x = (float) width / (float) mContentWidth;
- float y = (float) height / (float) mContentHeight;
- mZoomScrollLimit = Math.max(DEFAULT_MIN_ZOOM_SCALE, Math.min(x, y));
- mZoomScrollInvLimit = 1.0f / mZoomScrollLimit;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "canZoomScrollOut"
- + " mInvActualScale=" + mInvActualScale
- + " mZoomScrollLimit=" + mZoomScrollLimit
- + " mZoomScrollInvLimit=" + mZoomScrollInvLimit
- + " mContentWidth=" + mContentWidth
- + " mContentHeight=" + mContentHeight
- );
- }
- // don't zoom out unless magnify area is at least half as wide
- // or tall as content
- float limit = mZoomScrollLimit * 2;
- return mContentWidth >= width * limit
- || mContentHeight >= height * limit;
- }
-
- private void startZoomScrollOut() {
- setHorizontalScrollBarEnabled(false);
- setVerticalScrollBarEnabled(false);
- if (mZoomControlRunnable != null) {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- }
- if (mZoomControls != null) {
- mZoomControls.hide();
- }
- int width = getViewWidth();
- int height = getViewHeight();
- int halfW = width >> 1;
- mLastTouchX = halfW;
- int halfH = height >> 1;
- mLastTouchY = halfH;
- mScroller.abortAnimation();
- mZoomScrollStart = System.currentTimeMillis();
- Rect zoomFrame = scrollZoomFrame(width, height
- , scrollZoomMagScale(mZoomScrollInvLimit));
- mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale)
- - (zoomFrame.width() >> 1));
- mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale)
- - (zoomFrame.height() >> 1));
- scrollTo(0, 0); // triggers inval, starts animation
- clearTextEntry();
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=("
- + mZoomScrollX + ", " + mZoomScrollY +")");
- }
- }
-
- private void zoomScrollOut() {
- if (canZoomScrollOut() == false) {
- mTouchMode = TOUCH_DONE_MODE;
- return;
- }
- startZoomScrollOut();
- mTouchMode = SCROLL_ZOOM_ANIMATION_OUT;
- invalidate();
- }
-
- private void moveZoomScrollWindow(float x, float y) {
- if (Math.abs(x - mLastZoomScrollRawX) < 1.5f
- && Math.abs(y - mLastZoomScrollRawY) < 1.5f) {
- return;
- }
- mLastZoomScrollRawX = x;
- mLastZoomScrollRawY = y;
- int oldX = mZoomScrollX;
- int oldY = mZoomScrollY;
- int width = getViewWidth();
- int height = getViewHeight();
- int maxZoomX = mContentWidth - width;
- if (maxZoomX > 0) {
- int maxScreenX = width - (int) Math.ceil(width
- * mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveZoomScrollWindow-X"
- + " maxScreenX=" + maxScreenX + " width=" + width
- + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x);
- }
- x += maxScreenX * mLastScrollX / maxZoomX - mLastTouchX;
- x *= Math.max(maxZoomX / maxScreenX, mZoomScrollInvLimit);
- mZoomScrollX = Math.max(0, Math.min(maxZoomX, (int) x));
- }
- int maxZoomY = mContentHeight - height;
- if (maxZoomY > 0) {
- int maxScreenY = height - (int) Math.ceil(height
- * mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveZoomScrollWindow-Y"
- + " maxScreenY=" + maxScreenY + " height=" + height
- + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y);
- }
- y += maxScreenY * mLastScrollY / maxZoomY - mLastTouchY;
- y *= Math.max(maxZoomY / maxScreenY, mZoomScrollInvLimit);
- mZoomScrollY = Math.max(0, Math.min(maxZoomY, (int) y));
- }
- if (oldX != mZoomScrollX || oldY != mZoomScrollY) {
- invalidate();
- }
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveZoomScrollWindow"
- + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")"
- + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")"
- + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")"
- + " last=("+mLastScrollX+", "+mLastScrollY+")"
- + " x=" + x + " y=" + y);
- }
- }
-
- private void setZoomScrollIn() {
- mZoomScrollStart = System.currentTimeMillis();
- }
-
- private float mZoomScrollLimit;
- private float mZoomScrollInvLimit;
- private int mLastScrollX;
- private int mLastScrollY;
- private long mZoomScrollStart;
- private int mZoomScrollX;
- private int mZoomScrollY;
- private float mLastZoomScrollRawX = -1000.0f;
- private float mLastZoomScrollRawY = -1000.0f;
- // The zoomed scale varies from 1.0 to DEFAULT_MIN_ZOOM_SCALE == 0.25.
- // The zoom animation duration SCROLL_ZOOM_DURATION == 0.5.
- // Two pressures compete for gridding; a high frame rate (e.g. 20 fps)
- // and minimizing font cache allocations (fewer frames is better).
- // A SCROLL_ZOOM_GRID of 6 permits about 20 zoom levels over 0.5 seconds:
- // the inverse of: 1.0, 1.16, 1.33, 1.5, 1.67, 1.84, 2.0, etc. to 4.0
- private static final int SCROLL_ZOOM_GRID = 6;
- private static final int SCROLL_ZOOM_DURATION = 500;
- // Make it easier to get to the bottom of a document by reserving a 32
- // pixel buffer, for when the starting drag is a bit below the bottom of
- // the magnify frame.
- private static final int SCROLL_ZOOM_FINGER_BUFFER = 32;
-
- // draw history
- private boolean mDrawHistory = false;
- private Picture mHistoryPicture = null;
- private int mHistoryWidth = 0;
- private int mHistoryHeight = 0;
-
- // Only check the flag, can be called from WebCore thread
- boolean drawHistory() {
- return mDrawHistory;
- }
-
- // Should only be called in UI thread
- void switchOutDrawHistory() {
- if (null == mWebViewCore) return; // CallbackProxy may trigger this
- if (mDrawHistory) {
- mDrawHistory = false;
- invalidate();
- int oldScrollX = mScrollX;
- int oldScrollY = mScrollY;
- mScrollX = pinLocX(mScrollX);
- mScrollY = pinLocY(mScrollY);
- if (oldScrollX != mScrollX || oldScrollY != mScrollY) {
- mUserScroll = false;
- mWebViewCore.sendMessage(EventHub.SYNC_SCROLL, oldScrollX,
- oldScrollY);
- }
- sendOurVisibleRect();
- }
- }
-
- /**
- * Class representing the node which is focused.
- */
- private class FocusNode {
- public FocusNode() {
- mBounds = new Rect();
- }
- // Only to be called by JNI
- private void setAll(boolean isTextField, boolean isTextArea, boolean
- isPassword, boolean isAnchor, boolean isRtlText, int maxLength,
- int textSize, int boundsX, int boundsY, int boundsRight, int
- boundsBottom, int nodePointer, int framePointer, String text,
- String name, int rootTextGeneration) {
- mIsTextField = isTextField;
- mIsTextArea = isTextArea;
- mIsPassword = isPassword;
- mIsAnchor = isAnchor;
- mIsRtlText = isRtlText;
-
- mMaxLength = maxLength;
- mTextSize = textSize;
-
- mBounds.set(boundsX, boundsY, boundsRight, boundsBottom);
-
-
- mNodePointer = nodePointer;
- mFramePointer = framePointer;
- mText = text;
- mName = name;
- mRootTextGeneration = rootTextGeneration;
- }
- public boolean mIsTextField;
- public boolean mIsTextArea;
- public boolean mIsPassword;
- public boolean mIsAnchor;
- public boolean mIsRtlText;
-
- public int mSelectionStart;
- public int mSelectionEnd;
- public int mMaxLength;
- public int mTextSize;
-
- public Rect mBounds;
-
- public int mNodePointer;
- public int mFramePointer;
- public String mText;
- public String mName;
- public int mRootTextGeneration;
- }
-
- // Warning: ONLY use mFocusNode AFTER calling nativeUpdateFocusNode(),
- // and ONLY if it returns true;
- private FocusNode mFocusNode = new FocusNode();
-
- /**
- * Delete text from start to end in the focused textfield. If there is no
- * focus, or if start == end, silently fail. If start and end are out of
- * order, swap them.
- * @param start Beginning of selection to delete.
- * @param end End of selection to delete.
- */
- /* package */ void deleteSelection(int start, int end) {
- mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end,
- new WebViewCore.FocusData(mFocusData));
- }
-
- /**
- * Set the selection to (start, end) in the focused textfield. If start and
- * end are out of order, swap them.
- * @param start Beginning of selection.
- * @param end End of selection.
- */
- /* package */ void setSelection(int start, int end) {
- mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end,
- new WebViewCore.FocusData(mFocusData));
- }
-
- // Called by JNI when a touch event puts a textfield into focus.
- private void displaySoftKeyboard() {
- InputMethodManager imm = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(mTextEntry, 0);
- mTextEntry.enableScrollOnScreen(true);
- // Now we need to fake a touch event to place the cursor where the
- // user touched.
- AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams)
- mTextEntry.getLayoutParams();
- if (lp != null) {
- // Take the last touch and adjust for the location of the
- // TextDialog.
- float x = mLastTouchX - lp.x;
- float y = mLastTouchY - lp.y;
- mTextEntry.fakeTouchEvent(x, y);
- }
- }
-
- private void updateTextEntry() {
- if (mTextEntry == null) {
- mTextEntry = new TextDialog(mContext, WebView.this);
- // Initialize our generation number.
- mTextGeneration = 0;
- }
- // If we do not have focus, do nothing until we gain focus.
- if (!hasFocus() && !mTextEntry.hasFocus()
- || (mTouchMode >= FIRST_SCROLL_ZOOM
- && mTouchMode <= LAST_SCROLL_ZOOM)) {
- mNeedsUpdateTextEntry = true;
- return;
- }
- boolean alreadyThere = inEditingMode();
- if (0 == mNativeClass || !nativeUpdateFocusNode()) {
- if (alreadyThere) {
- mTextEntry.remove();
- }
- return;
- }
- FocusNode node = mFocusNode;
- if (!node.mIsTextField && !node.mIsTextArea) {
- if (alreadyThere) {
- mTextEntry.remove();
- }
- return;
- }
- mTextEntry.setTextSize(contentToView(node.mTextSize));
- Rect visibleRect = sendOurVisibleRect();
- // Note that sendOurVisibleRect calls viewToContent, so the coordinates
- // should be in content coordinates.
- if (!Rect.intersects(node.mBounds, visibleRect)) {
- // Node is not on screen, so do not bother.
- return;
- }
- int x = node.mBounds.left;
- int y = node.mBounds.top;
- int width = node.mBounds.width();
- int height = node.mBounds.height();
- if (alreadyThere && mTextEntry.isSameTextField(node.mNodePointer)) {
- // It is possible that we have the same textfield, but it has moved,
- // i.e. In the case of opening/closing the screen.
- // In that case, we need to set the dimensions, but not the other
- // aspects.
- // We also need to restore the selection, which gets wrecked by
- // calling setTextEntryRect.
- Spannable spannable = (Spannable) mTextEntry.getText();
- int start = Selection.getSelectionStart(spannable);
- int end = Selection.getSelectionEnd(spannable);
- setTextEntryRect(x, y, width, height);
- // If the text has been changed by webkit, update it. However, if
- // there has been more UI text input, ignore it. We will receive
- // another update when that text is recognized.
- if (node.mText != null && !node.mText.equals(spannable.toString())
- && node.mRootTextGeneration == mTextGeneration) {
- mTextEntry.setTextAndKeepSelection(node.mText);
- } else {
- Selection.setSelection(spannable, start, end);
- }
- } else {
- String text = node.mText;
- setTextEntryRect(x, y, width, height);
- mTextEntry.setGravity(node.mIsRtlText ? Gravity.RIGHT :
- Gravity.NO_GRAVITY);
- // this needs to be called before update adapter thread starts to
- // ensure the mTextEntry has the same node pointer
- mTextEntry.setNodePointer(node.mNodePointer);
- int maxLength = -1;
- if (node.mIsTextField) {
- maxLength = node.mMaxLength;
- if (mWebViewCore.getSettings().getSaveFormData()
- && node.mName != null) {
- HashMap data = new HashMap();
- data.put("text", node.mText);
- Message update = mPrivateHandler.obtainMessage(
- UPDATE_TEXT_ENTRY_ADAPTER, node.mNodePointer, 0,
- data);
- UpdateTextEntryAdapter updater = new UpdateTextEntryAdapter(
- node.mName, getUrl(), update);
- Thread t = new Thread(updater);
- t.start();
- }
- }
- mTextEntry.setMaxLength(maxLength);
- AutoCompleteAdapter adapter = null;
- mTextEntry.setAdapterCustom(adapter);
- mTextEntry.setSingleLine(node.mIsTextField);
- mTextEntry.setInPassword(node.mIsPassword);
- if (null == text) {
- mTextEntry.setText("", 0, 0);
- } else {
- // Change to true to enable the old style behavior, where
- // entering a textfield/textarea always set the selection to the
- // whole field. This was desirable for the case where the user
- // intends to scroll past the field using the trackball.
- // However, it causes a problem when replying to emails - the
- // user expects the cursor to be at the beginning of the
- // textarea. Testing out a new behavior, where textfields set
- // selection at the end, and textareas at the beginning.
- if (false) {
- mTextEntry.setText(text, 0, text.length());
- } else if (node.mIsTextField) {
- int length = text.length();
- mTextEntry.setText(text, length, length);
- } else {
- mTextEntry.setText(text, 0, 0);
- }
- }
- mTextEntry.requestFocus();
- }
- }
-
- private class UpdateTextEntryAdapter implements Runnable {
- private String mName;
- private String mUrl;
- private Message mUpdateMessage;
-
- public UpdateTextEntryAdapter(String name, String url, Message msg) {
- mName = name;
- mUrl = url;
- mUpdateMessage = msg;
- }
-
- public void run() {
- ArrayList<String> pastEntries = mDatabase.getFormData(mUrl, mName);
- if (pastEntries.size() > 0) {
- AutoCompleteAdapter adapter = new
- AutoCompleteAdapter(mContext, pastEntries);
- ((HashMap) mUpdateMessage.obj).put("adapter", adapter);
- mUpdateMessage.sendToTarget();
- }
- }
- }
-
- private void setTextEntryRect(int x, int y, int width, int height) {
- x = contentToView(x);
- y = contentToView(y);
- width = contentToView(width);
- height = contentToView(height);
- mTextEntry.setRect(x, y, width, height);
- }
-
- // This is used to determine long press with the enter key, or
- // a center key. Does not affect long press with the trackball/touch.
- private boolean mGotEnterDown = false;
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis()
- + ", " + event);
- }
-
- if (mNativeClass == 0) {
- return false;
- }
-
- // do this hack up front, so it always works, regardless of touch-mode
- if (AUTO_REDRAW_HACK && (keyCode == KeyEvent.KEYCODE_CALL)) {
- mAutoRedraw = !mAutoRedraw;
- if (mAutoRedraw) {
- invalidate();
- }
- return true;
- }
-
- // Bubble up the key event if
- // 1. it is a system key; or
- // 2. the host application wants to handle it; or
- // 3. webview is in scroll-zoom state;
- if (event.isSystem()
- || mCallbackProxy.uiOverrideKeyEvent(event)
- || (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM)) {
- return false;
- }
-
- if (mShiftIsPressed == false && nativeFocusNodeWantsKeyEvents() == false
- && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
- || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) {
- mExtendSelection = false;
- mShiftIsPressed = true;
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- mSelectX = contentToView(node.mBounds.left);
- mSelectY = contentToView(node.mBounds.top);
- } else {
- mSelectX = mScrollX + (int) mLastTouchX;
- mSelectY = mScrollY + (int) mLastTouchY;
- }
- }
-
- if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
- && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
- // always handle the navigation keys in the UI thread
- switchOutDrawHistory();
- if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
- playSoundEffect(keyCodeToSoundsEffect(keyCode));
- return true;
- }
- // Bubble up the key event as WebView doesn't handle it
- return false;
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_ENTER) {
- switchOutDrawHistory();
- if (event.getRepeatCount() == 0) {
- mGotEnterDown = true;
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(LONG_PRESS_ENTER), LONG_PRESS_TIMEOUT);
- // Already checked mNativeClass, so we do not need to check it
- // again.
- nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
- return true;
- }
- // Bubble up the key event as WebView doesn't handle it
- return false;
- }
-
- if (getSettings().getNavDump()) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_4:
- // "/data/data/com.android.browser/displayTree.txt"
- nativeDumpDisplayTree(getUrl());
- break;
- case KeyEvent.KEYCODE_5:
- case KeyEvent.KEYCODE_6:
- // 5: dump the dom tree to the file
- // "/data/data/com.android.browser/domTree.txt"
- // 6: dump the dom tree to the adb log
- mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE,
- (keyCode == KeyEvent.KEYCODE_5) ? 1 : 0, 0);
- break;
- case KeyEvent.KEYCODE_7:
- case KeyEvent.KEYCODE_8:
- // 7: dump the render tree to the file
- // "/data/data/com.android.browser/renderTree.txt"
- // 8: dump the render tree to the adb log
- mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE,
- (keyCode == KeyEvent.KEYCODE_7) ? 1 : 0, 0);
- break;
- case KeyEvent.KEYCODE_9:
- nativeInstrumentReport();
- return true;
- }
- }
-
- // TODO: should we pass all the keys to DOM or check the meta tag
- if (nativeFocusNodeWantsKeyEvents() || true) {
- // pass the key to DOM
- mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
- // return true as DOM handles the key
- return true;
- }
-
- // Bubble up the key event as WebView doesn't handle it
- return false;
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis()
- + ", " + event);
- }
-
- if (mNativeClass == 0) {
- return false;
- }
-
- // special CALL handling when focus node's href is "tel:XXX"
- if (keyCode == KeyEvent.KEYCODE_CALL && nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- String text = node.mText;
- if (!node.mIsTextField && !node.mIsTextArea && text != null
- && text.startsWith(SCHEME_TEL)) {
- Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text));
- getContext().startActivity(intent);
- return true;
- }
- }
-
- // Bubble up the key event if
- // 1. it is a system key; or
- // 2. the host application wants to handle it;
- if (event.isSystem() || mCallbackProxy.uiOverrideKeyEvent(event)) {
- return false;
- }
-
- // special handling in scroll_zoom state
- if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
- if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode
- && mTouchMode != SCROLL_ZOOM_ANIMATION_IN) {
- setZoomScrollIn();
- mTouchMode = SCROLL_ZOOM_ANIMATION_IN;
- invalidate();
- return true;
- }
- return false;
- }
-
- if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
- || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
- if (commitCopy()) {
- return true;
- }
- }
-
- if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
- && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
- // always handle the navigation keys in the UI thread
- // Bubble up the key event as WebView doesn't handle it
- return false;
- }
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_ENTER) {
- // remove the long press message first
- mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
- mGotEnterDown = false;
-
- if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
- if (mShiftIsPressed) {
- return false;
- }
- if (getSettings().supportZoom()) {
- if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
- zoomScrollOut();
- } else {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
- }
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT);
- mTouchMode = TOUCH_DOUBLECLICK_MODE;
- }
- return true;
- }
- }
-
- Rect visibleRect = sendOurVisibleRect();
- // Note that sendOurVisibleRect calls viewToContent, so the
- // coordinates should be in content coordinates.
- if (nativeUpdateFocusNode()) {
- if (Rect.intersects(mFocusNode.mBounds, visibleRect)) {
- nativeSetFollowedLink(true);
- mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
- EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0,
- new WebViewCore.FocusData(mFocusData));
- playSoundEffect(SoundEffectConstants.CLICK);
- if (!mCallbackProxy.uiOverrideUrlLoading(mFocusNode.mText)) {
- // use CLICK instead of KEY_DOWN/KEY_UP so that we can
- // trigger mouse click events
- mWebViewCore.sendMessage(EventHub.CLICK);
- }
- }
- return true;
- }
- // Bubble up the key event as WebView doesn't handle it
- return false;
- }
-
- // TODO: should we pass all the keys to DOM or check the meta tag
- if (nativeFocusNodeWantsKeyEvents() || true) {
- // pass the key to DOM
- mWebViewCore.sendMessage(EventHub.KEY_UP, event);
- // return true as DOM handles the key
- return true;
- }
-
- // Bubble up the key event as WebView doesn't handle it
- return false;
- }
-
- /**
- * @hide
- */
- public void emulateShiftHeld() {
- mExtendSelection = false;
- mShiftIsPressed = true;
- }
-
- private boolean commitCopy() {
- boolean copiedSomething = false;
- if (mExtendSelection) {
- // copy region so core operates on copy without touching orig.
- Region selection = new Region(nativeGetSelection());
- if (selection.isEmpty() == false) {
- Toast.makeText(mContext
- , com.android.internal.R.string.text_copied
- , Toast.LENGTH_SHORT).show();
- mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection);
- copiedSomething = true;
- }
- mExtendSelection = false;
- }
- mShiftIsPressed = false;
- if (mTouchMode == TOUCH_SELECT_MODE) {
- mTouchMode = TOUCH_INIT_MODE;
- }
- return copiedSomething;
- }
-
- // Set this as a hierarchy change listener so we can know when this view
- // is removed and still have access to our parent.
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- ViewParent parent = getParent();
- if (parent instanceof ViewGroup) {
- ViewGroup p = (ViewGroup) parent;
- p.setOnHierarchyChangeListener(this);
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- ViewParent parent = getParent();
- if (parent instanceof ViewGroup) {
- ViewGroup p = (ViewGroup) parent;
- p.setOnHierarchyChangeListener(null);
- }
-
- // Clean up the zoom ring
- mZoomRingController.setVisible(false);
- }
-
- // Implementation for OnHierarchyChangeListener
- public void onChildViewAdded(View parent, View child) {}
-
- public void onChildViewRemoved(View p, View child) {
- if (child == this) {
- if (inEditingMode()) {
- clearTextEntry();
- mNeedsUpdateTextEntry = true;
- }
- }
- }
-
- /**
- * @deprecated WebView should not have implemented
- * ViewTreeObserver.OnGlobalFocusChangeListener. This method
- * does nothing now.
- */
- @Deprecated
- public void onGlobalFocusChanged(View oldFocus, View newFocus) {
- }
-
- // To avoid drawing the focus ring, and remove the TextView when our window
- // loses focus.
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- if (hasWindowFocus) {
- if (hasFocus()) {
- // If our window regained focus, and we have focus, then begin
- // drawing the focus ring, and restore the TextView if
- // necessary.
- mDrawFocusRing = true;
- if (mNeedsUpdateTextEntry) {
- updateTextEntry();
- }
- if (mNativeClass != 0) {
- nativeRecordButtons(true, false, true);
- }
- } else {
- // If our window gained focus, but we do not have it, do not
- // draw the focus ring.
- mDrawFocusRing = false;
- // We do not call nativeRecordButtons here because we assume
- // that when we lost focus, or window focus, it got called with
- // false for the first parameter
- }
- } else {
- // If our window has lost focus, stop drawing the focus ring
- mDrawFocusRing = false;
- mGotKeyDown = false;
- mShiftIsPressed = false;
- if (mNativeClass != 0) {
- nativeRecordButtons(false, false, true);
- }
- }
- invalidate();
- super.onWindowFocusChanged(hasWindowFocus);
- }
-
- @Override
- protected void onFocusChanged(boolean focused, int direction,
- Rect previouslyFocusedRect) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "MT focusChanged " + focused + ", " + direction);
- }
- if (focused) {
- // When we regain focus, if we have window focus, resume drawing
- // the focus ring, and add the TextView if necessary.
- if (hasWindowFocus()) {
- mDrawFocusRing = true;
- if (mNeedsUpdateTextEntry) {
- updateTextEntry();
- mNeedsUpdateTextEntry = false;
- }
- if (mNativeClass != 0) {
- nativeRecordButtons(true, false, true);
- }
- //} else {
- // The WebView has gained focus while we do not have
- // windowfocus. When our window lost focus, we should have
- // called nativeRecordButtons(false...)
- }
- } else {
- // When we lost focus, unless focus went to the TextView (which is
- // true if we are in editing mode), stop drawing the focus ring.
- if (!inEditingMode()) {
- mDrawFocusRing = false;
- if (mNativeClass != 0) {
- nativeRecordButtons(false, false, true);
- }
- }
- mGotKeyDown = false;
- }
-
- super.onFocusChanged(focused, direction, previouslyFocusedRect);
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int ow, int oh) {
- super.onSizeChanged(w, h, ow, oh);
- // Center zooming to the center of the screen. This is appropriate for
- // this case of zooming, and it also sets us up properly if we remove
- // the new zoom ring controller
- mZoomCenterX = getViewWidth() * .5f;
- mZoomCenterY = getViewHeight() * .5f;
-
- // update mMinZoomScale
- if (mMinContentWidth > MAX_FLOAT_CONTENT_WIDTH) {
- boolean atMin = Math.abs(mActualScale - mMinZoomScale) < 0.01f;
- mMinZoomScale = (float) getViewWidth() / mContentWidth;
- if (atMin) {
- // if the WebView was at the minimum zoom scale, keep it. e,g.,
- // the WebView was at the minimum zoom scale at the portrait
- // mode, rotate it to the landscape modifying the scale to the
- // new minimum zoom scale, when rotating back, we would like to
- // keep the minimum zoom scale instead of keeping the same scale
- // as normally we do.
- mActualScale = mMinZoomScale;
- }
- }
-
- // we always force, in case our height changed, in which case we still
- // want to send the notification over to webkit
- setNewZoomScale(mActualScale, true);
- }
-
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt) {
- super.onScrollChanged(l, t, oldl, oldt);
- sendOurVisibleRect();
- }
-
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- boolean dispatch = true;
-
- if (!inEditingMode()) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- mGotKeyDown = true;
- } else {
- if (!mGotKeyDown) {
- /*
- * We got a key up for which we were not the recipient of
- * the original key down. Don't give it to the view.
- */
- dispatch = false;
- }
- mGotKeyDown = false;
- }
- }
-
- if (dispatch) {
- return super.dispatchKeyEvent(event);
- } else {
- // We didn't dispatch, so let something else handle the key
- return false;
- }
- }
-
- // Here are the snap align logic:
- // 1. If it starts nearly horizontally or vertically, snap align;
- // 2. If there is a dramitic direction change, let it go;
- // 3. If there is a same direction back and forth, lock it.
-
- // adjustable parameters
- private int mMinLockSnapReverseDistance;
- private static final float MAX_SLOPE_FOR_DIAG = 1.5f;
- private static final int MIN_BREAK_SNAP_CROSS_DISTANCE = 80;
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (mNativeClass == 0 || !isClickable() || !isLongClickable()) {
- return false;
- }
-
- if (mShowZoomRingTutorial && getSettings().supportZoom()
- && (mMaxZoomScale - mMinZoomScale) > ZOOM_RING_STEPS * 0.01f) {
- ZoomRingController.showZoomTutorialOnce(mContext);
- mShowZoomRingTutorial = false;
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(DISMISS_ZOOM_RING_TUTORIAL),
- ZOOM_RING_TUTORIAL_DURATION);
- }
-
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, ev + " at " + ev.getEventTime() + " mTouchMode="
- + mTouchMode);
- }
-
- if (mZoomRingController.isVisible() && mInZoomTapDragMode) {
- if (ev.getAction() == MotionEvent.ACTION_UP) {
- // Just released the second tap, no longer in tap-drag mode
- mInZoomTapDragMode = false;
- }
- return mZoomRingController.handleDoubleTapEvent(ev);
- }
-
- int action = ev.getAction();
- float x = ev.getX();
- float y = ev.getY();
- long eventTime = ev.getEventTime();
-
- // Due to the touch screen edge effect, a touch closer to the edge
- // always snapped to the edge. As getViewWidth() can be different from
- // getWidth() due to the scrollbar, adjusting the point to match
- // getViewWidth(). Same applied to the height.
- if (x > getViewWidth() - 1) {
- x = getViewWidth() - 1;
- }
- if (y > getViewHeight() - 1) {
- y = getViewHeight() - 1;
- }
-
- // pass the touch events from UI thread to WebCore thread
- if (mForwardTouchEvents && mTouchMode != SCROLL_ZOOM_OUT
- && mTouchMode != SCROLL_ZOOM_ANIMATION_IN
- && mTouchMode != SCROLL_ZOOM_ANIMATION_OUT
- && (action != MotionEvent.ACTION_MOVE ||
- eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
- WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
- ted.mAction = action;
- ted.mX = viewToContent((int) x + mScrollX);
- ted.mY = viewToContent((int) y + mScrollY);;
- mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
- mLastSentTouchTime = eventTime;
- }
-
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
- if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN
- || mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
- // no interaction while animation is in progress
- break;
- } else if (mTouchMode == SCROLL_ZOOM_OUT) {
- mLastScrollX = mZoomScrollX;
- mLastScrollY = mZoomScrollY;
- // If two taps are close, ignore the first tap
- } else if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- mTouchMode = TOUCH_DRAG_START_MODE;
- mPrivateHandler.removeMessages(RESUME_WEBCORE_UPDATE);
- } else if (mShiftIsPressed) {
- mSelectX = mScrollX + (int) x;
- mSelectY = mScrollY + (int) y;
- mTouchMode = TOUCH_SELECT_MODE;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "select=" + mSelectX + "," + mSelectY);
- }
- nativeMoveSelection(viewToContent(mSelectX)
- , viewToContent(mSelectY), false);
- mTouchSelection = mExtendSelection = true;
- } else if (!ZoomRingController.useOldZoom(mContext) &&
- mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
- // Found doubletap, invoke the zoom controller
- mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
- mZoomRingController.setVisible(true);
- mInZoomTapDragMode = true;
- if (mLogEvent) {
- EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
- (eventTime - mLastTouchUpTime), eventTime);
- }
- return mZoomRingController.handleDoubleTapEvent(ev);
- } else {
- mTouchMode = TOUCH_INIT_MODE;
- mPreventDrag = mForwardTouchEvents;
- if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
- EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
- (eventTime - mLastTouchUpTime), eventTime);
- }
- }
- // don't trigger the link if zoom ring is visible
- if (mTouchMode == TOUCH_INIT_MODE
- && !mZoomRingController.isVisible()) {
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
- }
- // Remember where the motion event started
- mLastTouchX = x;
- mLastTouchY = y;
- mLastTouchTime = eventTime;
- mVelocityTracker = VelocityTracker.obtain();
- mSnapScrollMode = SNAP_NONE;
- break;
- }
- case MotionEvent.ACTION_MOVE: {
- if (mTouchMode == TOUCH_DONE_MODE
- || mTouchMode == SCROLL_ZOOM_ANIMATION_IN
- || mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
- // no dragging during scroll zoom animation
- break;
- }
- if (mTouchMode == SCROLL_ZOOM_OUT) {
- // while fully zoomed out, move the virtual window
- moveZoomScrollWindow(x, y);
- break;
- }
- mVelocityTracker.addMovement(ev);
-
- int deltaX = (int) (mLastTouchX - x);
- int deltaY = (int) (mLastTouchY - y);
-
- if (mTouchMode != TOUCH_DRAG_MODE) {
- if (mTouchMode == TOUCH_SELECT_MODE) {
- mSelectX = mScrollX + (int) x;
- mSelectY = mScrollY + (int) y;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "xtend=" + mSelectX + "," + mSelectY);
- }
- nativeMoveSelection(viewToContent(mSelectX)
- , viewToContent(mSelectY), true);
- invalidate();
- break;
- }
- if (mPreventDrag || (deltaX * deltaX + deltaY * deltaY)
- < mTouchSlopSquare) {
- break;
- }
-
- if (mTouchMode == TOUCH_SHORTPRESS_MODE
- || mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
- mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- } else if (mTouchMode == TOUCH_INIT_MODE) {
- mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
- }
-
- // if it starts nearly horizontal or vertical, enforce it
- int ax = Math.abs(deltaX);
- int ay = Math.abs(deltaY);
- if (ax > MAX_SLOPE_FOR_DIAG * ay) {
- mSnapScrollMode = SNAP_X;
- mSnapPositive = deltaX > 0;
- } else if (ay > MAX_SLOPE_FOR_DIAG * ax) {
- mSnapScrollMode = SNAP_Y;
- mSnapPositive = deltaY > 0;
- }
-
- mTouchMode = TOUCH_DRAG_MODE;
- WebViewCore.pauseUpdate(mWebViewCore);
- int contentX = viewToContent((int) x + mScrollX);
- int contentY = viewToContent((int) y + mScrollY);
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
- nativeClearFocus(contentX, contentY);
- // remove the zoom anchor if there is any
- if (mZoomScale != 0) {
- mWebViewCore
- .sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
- }
- }
-
- // do pan
- int newScrollX = pinLocX(mScrollX + deltaX);
- deltaX = newScrollX - mScrollX;
- int newScrollY = pinLocY(mScrollY + deltaY);
- deltaY = newScrollY - mScrollY;
- boolean done = false;
- if (deltaX == 0 && deltaY == 0) {
- done = true;
- } else {
- if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
- int ax = Math.abs(deltaX);
- int ay = Math.abs(deltaY);
- if (mSnapScrollMode == SNAP_X) {
- // radical change means getting out of snap mode
- if (ay > MAX_SLOPE_FOR_DIAG * ax
- && ay > MIN_BREAK_SNAP_CROSS_DISTANCE) {
- mSnapScrollMode = SNAP_NONE;
- }
- // reverse direction means lock in the snap mode
- if ((ax > MAX_SLOPE_FOR_DIAG * ay) &&
- ((mSnapPositive &&
- deltaX < -mMinLockSnapReverseDistance)
- || (!mSnapPositive &&
- deltaX > mMinLockSnapReverseDistance))) {
- mSnapScrollMode = SNAP_X_LOCK;
- }
- } else {
- // radical change means getting out of snap mode
- if ((ax > MAX_SLOPE_FOR_DIAG * ay)
- && ax > MIN_BREAK_SNAP_CROSS_DISTANCE) {
- mSnapScrollMode = SNAP_NONE;
- }
- // reverse direction means lock in the snap mode
- if ((ay > MAX_SLOPE_FOR_DIAG * ax) &&
- ((mSnapPositive &&
- deltaY < -mMinLockSnapReverseDistance)
- || (!mSnapPositive &&
- deltaY > mMinLockSnapReverseDistance))) {
- mSnapScrollMode = SNAP_Y_LOCK;
- }
- }
- }
-
- if (mSnapScrollMode == SNAP_X
- || mSnapScrollMode == SNAP_X_LOCK) {
- scrollBy(deltaX, 0);
- mLastTouchX = x;
- } else if (mSnapScrollMode == SNAP_Y
- || mSnapScrollMode == SNAP_Y_LOCK) {
- scrollBy(0, deltaY);
- mLastTouchY = y;
- } else {
- scrollBy(deltaX, deltaY);
- mLastTouchX = x;
- mLastTouchY = y;
- }
- mLastTouchTime = eventTime;
- mUserScroll = true;
- }
-
- if (ZoomRingController.useOldZoom(mContext)) {
- boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
- boolean showMagnify = canZoomScrollOut();
- if (mZoomControls != null && (showPlusMinus || showMagnify)) {
- if (mZoomControls.getVisibility() == View.VISIBLE) {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- } else {
- mZoomControls.show(showPlusMinus, showMagnify);
- }
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- }
- }
- if (done) {
- // return false to indicate that we can't pan out of the
- // view space
- return false;
- }
- break;
- }
- case MotionEvent.ACTION_UP: {
- mLastTouchUpTime = eventTime;
- switch (mTouchMode) {
- case TOUCH_INIT_MODE: // tap
- if (mZoomRingController.isVisible()) {
- // don't trigger the link if zoom ring is visible,
- // but still allow the double tap
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(RELEASE_SINGLE_TAP,
- new Boolean(false)),
- DOUBLE_TAP_TIMEOUT);
- break;
- }
- mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
- if (getSettings().supportZoom()) {
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(RELEASE_SINGLE_TAP,
- new Boolean(true)),
- DOUBLE_TAP_TIMEOUT);
- } else {
- // do short press now
- mTouchMode = TOUCH_DONE_MODE;
- doShortPress();
- }
- break;
- case TOUCH_SELECT_MODE:
- commitCopy();
- mTouchSelection = false;
- break;
- case SCROLL_ZOOM_ANIMATION_IN:
- case SCROLL_ZOOM_ANIMATION_OUT:
- // no action during scroll animation
- break;
- case SCROLL_ZOOM_OUT:
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "ACTION_UP SCROLL_ZOOM_OUT"
- + " eventTime - mLastTouchTime="
- + (eventTime - mLastTouchTime));
- }
- // for now, always zoom back when the drag completes
- if (true || eventTime - mLastTouchTime < TAP_TIMEOUT) {
- // but if we tap, zoom in where we tap
- if (eventTime - mLastTouchTime < TAP_TIMEOUT) {
- zoomScrollTap(x, y);
- }
- // start zooming in back to the original view
- setZoomScrollIn();
- mTouchMode = SCROLL_ZOOM_ANIMATION_IN;
- invalidate();
- }
- break;
- case TOUCH_SHORTPRESS_START_MODE:
- case TOUCH_SHORTPRESS_MODE: {
- mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- if (eventTime - mLastTouchTime < TAP_TIMEOUT
- && getSettings().supportZoom()) {
- // Note: window manager will not release ACTION_UP
- // until all the previous action events are
- // returned. If GC happens, it can cause
- // SWITCH_TO_SHORTPRESS message fired before
- // ACTION_UP sent even time stamp of ACTION_UP is
- // less than the tap time out. We need to treat this
- // as tap instead of short press.
- mTouchMode = TOUCH_INIT_MODE;
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(RELEASE_SINGLE_TAP,
- new Boolean(true)),
- DOUBLE_TAP_TIMEOUT);
- } else {
- mTouchMode = TOUCH_DONE_MODE;
- doShortPress();
- }
- break;
- }
- case TOUCH_DRAG_MODE:
- // if the user waits a while w/o moving before the
- // up, we don't want to do a fling
- if (eventTime - mLastTouchTime <= MIN_FLING_TIME) {
- mVelocityTracker.addMovement(ev);
- doFling();
- break;
- }
- WebViewCore.resumeUpdate(mWebViewCore);
- break;
- case TOUCH_DRAG_START_MODE:
- case TOUCH_DONE_MODE:
- // do nothing
- break;
- }
- // we also use mVelocityTracker == null to tell us that we are
- // not "moving around", so we can take the slower/prettier
- // mode in the drawing code
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- break;
- }
- case MotionEvent.ACTION_CANCEL: {
- // we also use mVelocityTracker == null to tell us that we are
- // not "moving around", so we can take the slower/prettier
- // mode in the drawing code
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- if (mTouchMode == SCROLL_ZOOM_OUT ||
- mTouchMode == SCROLL_ZOOM_ANIMATION_IN) {
- scrollTo(mZoomScrollX, mZoomScrollY);
- } else if (mTouchMode == TOUCH_DRAG_MODE) {
- WebViewCore.resumeUpdate(mWebViewCore);
- }
- mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
- mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
- mTouchMode = TOUCH_DONE_MODE;
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
- nativeClearFocus(contentX, contentY);
- break;
- }
- }
- return true;
- }
-
- private long mTrackballFirstTime = 0;
- private long mTrackballLastTime = 0;
- private float mTrackballRemainsX = 0.0f;
- private float mTrackballRemainsY = 0.0f;
- private int mTrackballXMove = 0;
- private int mTrackballYMove = 0;
- private boolean mExtendSelection = false;
- private boolean mTouchSelection = false;
- private static final int TRACKBALL_KEY_TIMEOUT = 1000;
- private static final int TRACKBALL_TIMEOUT = 200;
- private static final int TRACKBALL_WAIT = 100;
- private static final int TRACKBALL_SCALE = 400;
- private static final int TRACKBALL_SCROLL_COUNT = 5;
- private static final int TRACKBALL_MOVE_COUNT = 10;
- private static final int TRACKBALL_MULTIPLIER = 3;
- private static final int SELECT_CURSOR_OFFSET = 16;
- private int mSelectX = 0;
- private int mSelectY = 0;
- private boolean mShiftIsPressed = false;
- private boolean mTrackballDown = false;
- private long mTrackballUpTime = 0;
- private long mLastFocusTime = 0;
- private Rect mLastFocusBounds;
-
- // Set by default; BrowserActivity clears to interpret trackball data
- // directly for movement. Currently, the framework only passes
- // arrow key events, not trackball events, from one child to the next
- private boolean mMapTrackballToArrowKeys = true;
-
- public void setMapTrackballToArrowKeys(boolean setMap) {
- mMapTrackballToArrowKeys = setMap;
- }
-
- void resetTrackballTime() {
- mTrackballLastTime = 0;
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent ev) {
- long time = ev.getEventTime();
- if ((ev.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
- if (ev.getY() > 0) pageDown(true);
- if (ev.getY() < 0) pageUp(true);
- return true;
- }
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mPrivateHandler.removeMessages(SWITCH_TO_ENTER);
- mTrackballDown = true;
- if (mNativeClass != 0) {
- nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
- }
- if (time - mLastFocusTime <= TRACKBALL_TIMEOUT
- && !mLastFocusBounds.equals(nativeGetFocusRingBounds())) {
- nativeSelectBestAt(mLastFocusBounds);
- }
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "onTrackballEvent down ev=" + ev
- + " time=" + time
- + " mLastFocusTime=" + mLastFocusTime);
- }
- if (isInTouchMode()) requestFocusFromTouch();
- return false; // let common code in onKeyDown at it
- }
- if (ev.getAction() == MotionEvent.ACTION_UP) {
- // LONG_PRESS_ENTER is set in common onKeyDown
- mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
- mTrackballDown = false;
- mTrackballUpTime = time;
- if (mShiftIsPressed) {
- if (mExtendSelection) {
- commitCopy();
- } else {
- mExtendSelection = true;
- }
- }
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "onTrackballEvent up ev=" + ev
- + " time=" + time
- );
- }
- return false; // let common code in onKeyUp at it
- }
- if (mMapTrackballToArrowKeys && mShiftIsPressed == false) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent gmail quit");
- return false;
- }
- // no move if we're still waiting on SWITCH_TO_ENTER timeout
- if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent 2 click quit");
- return true;
- }
- if (mTrackballDown) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent down quit");
- return true; // discard move if trackball is down
- }
- if (time - mTrackballUpTime < TRACKBALL_TIMEOUT) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent up timeout quit");
- return true;
- }
- // TODO: alternatively we can do panning as touch does
- switchOutDrawHistory();
- if (time - mTrackballLastTime > TRACKBALL_TIMEOUT) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "onTrackballEvent time="
- + time + " last=" + mTrackballLastTime);
- }
- mTrackballFirstTime = time;
- mTrackballXMove = mTrackballYMove = 0;
- }
- mTrackballLastTime = time;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "onTrackballEvent ev=" + ev + " time=" + time);
- }
- mTrackballRemainsX += ev.getX();
- mTrackballRemainsY += ev.getY();
- doTrackball(time);
- return true;
- }
-
- void moveSelection(float xRate, float yRate) {
- if (mNativeClass == 0)
- return;
- int width = getViewWidth();
- int height = getViewHeight();
- mSelectX += scaleTrackballX(xRate, width);
- mSelectY += scaleTrackballY(yRate, height);
- int maxX = width + mScrollX;
- int maxY = height + mScrollY;
- mSelectX = Math.min(maxX, Math.max(mScrollX - SELECT_CURSOR_OFFSET
- , mSelectX));
- mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
- , mSelectY));
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveSelection"
- + " mSelectX=" + mSelectX
- + " mSelectY=" + mSelectY
- + " mScrollX=" + mScrollX
- + " mScrollY=" + mScrollY
- + " xRate=" + xRate
- + " yRate=" + yRate
- );
- }
- nativeMoveSelection(viewToContent(mSelectX)
- , viewToContent(mSelectY), mExtendSelection);
- int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
- : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
- : 0;
- int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
- : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
- : 0;
- pinScrollBy(scrollX, scrollY, true, 0);
- Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
- requestRectangleOnScreen(select);
- invalidate();
- }
-
- private int scaleTrackballX(float xRate, int width) {
- int xMove = (int) (xRate / TRACKBALL_SCALE * width);
- int nextXMove = xMove;
- if (xMove > 0) {
- if (xMove > mTrackballXMove) {
- xMove -= mTrackballXMove;
- }
- } else if (xMove < mTrackballXMove) {
- xMove -= mTrackballXMove;
- }
- mTrackballXMove = nextXMove;
- return xMove;
- }
-
- private int scaleTrackballY(float yRate, int height) {
- int yMove = (int) (yRate / TRACKBALL_SCALE * height);
- int nextYMove = yMove;
- if (yMove > 0) {
- if (yMove > mTrackballYMove) {
- yMove -= mTrackballYMove;
- }
- } else if (yMove < mTrackballYMove) {
- yMove -= mTrackballYMove;
- }
- mTrackballYMove = nextYMove;
- return yMove;
- }
-
- private int keyCodeToSoundsEffect(int keyCode) {
- switch(keyCode) {
- case KeyEvent.KEYCODE_DPAD_UP:
- return SoundEffectConstants.NAVIGATION_UP;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- return SoundEffectConstants.NAVIGATION_RIGHT;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- return SoundEffectConstants.NAVIGATION_DOWN;
- case KeyEvent.KEYCODE_DPAD_LEFT:
- return SoundEffectConstants.NAVIGATION_LEFT;
- }
- throw new IllegalArgumentException("keyCode must be one of " +
- "{KEYCODE_DPAD_UP, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_DOWN, " +
- "KEYCODE_DPAD_LEFT}.");
- }
-
- private void doTrackball(long time) {
- int elapsed = (int) (mTrackballLastTime - mTrackballFirstTime);
- if (elapsed == 0) {
- elapsed = TRACKBALL_TIMEOUT;
- }
- float xRate = mTrackballRemainsX * 1000 / elapsed;
- float yRate = mTrackballRemainsY * 1000 / elapsed;
- if (mShiftIsPressed) {
- moveSelection(xRate, yRate);
- mTrackballRemainsX = mTrackballRemainsY = 0;
- return;
- }
- float ax = Math.abs(xRate);
- float ay = Math.abs(yRate);
- float maxA = Math.max(ax, ay);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "doTrackball elapsed=" + elapsed
- + " xRate=" + xRate
- + " yRate=" + yRate
- + " mTrackballRemainsX=" + mTrackballRemainsX
- + " mTrackballRemainsY=" + mTrackballRemainsY);
- }
- int width = mContentWidth - getViewWidth();
- int height = mContentHeight - getViewHeight();
- if (width < 0) width = 0;
- if (height < 0) height = 0;
- if (mTouchMode == SCROLL_ZOOM_OUT) {
- int oldX = mZoomScrollX;
- int oldY = mZoomScrollY;
- int maxWH = Math.max(width, height);
- mZoomScrollX += scaleTrackballX(xRate, maxWH);
- mZoomScrollY += scaleTrackballY(yRate, maxWH);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "doTrackball SCROLL_ZOOM_OUT"
- + " mZoomScrollX=" + mZoomScrollX
- + " mZoomScrollY=" + mZoomScrollY);
- }
- mZoomScrollX = Math.min(width, Math.max(0, mZoomScrollX));
- mZoomScrollY = Math.min(height, Math.max(0, mZoomScrollY));
- if (oldX != mZoomScrollX || oldY != mZoomScrollY) {
- invalidate();
- }
- mTrackballRemainsX = mTrackballRemainsY = 0;
- return;
- }
- ax = Math.abs(mTrackballRemainsX * TRACKBALL_MULTIPLIER);
- ay = Math.abs(mTrackballRemainsY * TRACKBALL_MULTIPLIER);
- maxA = Math.max(ax, ay);
- int count = Math.max(0, (int) maxA);
- int oldScrollX = mScrollX;
- int oldScrollY = mScrollY;
- if (count > 0) {
- int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
- KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
- mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT :
- KeyEvent.KEYCODE_DPAD_RIGHT;
- count = Math.min(count, TRACKBALL_MOVE_COUNT);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
- + " count=" + count
- + " mTrackballRemainsX=" + mTrackballRemainsX
- + " mTrackballRemainsY=" + mTrackballRemainsY);
- }
- if (navHandledKey(selectKeyCode, count, false, time)) {
- playSoundEffect(keyCodeToSoundsEffect(selectKeyCode));
- }
- mTrackballRemainsX = mTrackballRemainsY = 0;
- }
- if (count >= TRACKBALL_SCROLL_COUNT) {
- int xMove = scaleTrackballX(xRate, width);
- int yMove = scaleTrackballY(yRate, height);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "doTrackball pinScrollBy"
- + " count=" + count
- + " xMove=" + xMove + " yMove=" + yMove
- + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
- + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
- );
- }
- if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) {
- xMove = 0;
- }
- if (Math.abs(mScrollY - oldScrollY) > Math.abs(yMove)) {
- yMove = 0;
- }
- if (xMove != 0 || yMove != 0) {
- pinScrollBy(xMove, yMove, true, 0);
- }
- mUserScroll = true;
- }
- mWebViewCore.sendMessage(EventHub.UNBLOCK_FOCUS);
- }
-
- public void flingScroll(int vx, int vy) {
- int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0);
- int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0);
-
- mScroller.fling(mScrollX, mScrollY, vx, vy, 0, maxX, 0, maxY);
- invalidate();
- }
-
- private void doFling() {
- if (mVelocityTracker == null) {
- return;
- }
- int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0);
- int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0);
-
- mVelocityTracker.computeCurrentVelocity(1000);
- int vx = (int) mVelocityTracker.getXVelocity();
- int vy = (int) mVelocityTracker.getYVelocity();
-
- if (mSnapScrollMode != SNAP_NONE) {
- if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_X_LOCK) {
- vy = 0;
- } else {
- vx = 0;
- }
- }
-
- if (true /* EMG release: make our fling more like Maps' */) {
- // maps cuts their velocity in half
- vx = vx * 3 / 4;
- vy = vy * 3 / 4;
- }
-
- mScroller.fling(mScrollX, mScrollY, -vx, -vy, 0, maxX, 0, maxY);
- // TODO: duration is calculated based on velocity, if the range is
- // small, the animation will stop before duration is up. We may
- // want to calculate how long the animation is going to run to precisely
- // resume the webcore update.
- final int time = mScroller.getDuration();
- mPrivateHandler.sendEmptyMessageDelayed(RESUME_WEBCORE_UPDATE, time);
- invalidate();
- }
-
- private boolean zoomWithPreview(float scale) {
- float oldScale = mActualScale;
-
- // snap to 100% if it is close
- if (scale > 0.95f && scale < 1.05f) {
- scale = 1.0f;
- }
-
- setNewZoomScale(scale, false);
-
- if (oldScale != mActualScale) {
- // use mZoomPickerScale to see zoom preview first
- mZoomStart = SystemClock.uptimeMillis();
- mInvInitialZoomScale = 1.0f / oldScale;
- mInvFinalZoomScale = 1.0f / mActualScale;
- mZoomScale = mActualScale;
- invalidate();
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Returns a view containing zoom controls i.e. +/- buttons. The caller is
- * in charge of installing this view to the view hierarchy. This view will
- * become visible when the user starts scrolling via touch and fade away if
- * the user does not interact with it.
- */
- public View getZoomControls() {
- if (!getSettings().supportZoom()) {
- Log.w(LOGTAG, "This WebView doesn't support zoom.");
- return null;
- }
- if (mZoomControls == null) {
- mZoomControls = createZoomControls();
-
- /*
- * need to be set to VISIBLE first so that getMeasuredHeight() in
- * {@link #onSizeChanged()} can return the measured value for proper
- * layout.
- */
- mZoomControls.setVisibility(View.VISIBLE);
- mZoomControlRunnable = new Runnable() {
- public void run() {
-
- /* Don't dismiss the controls if the user has
- * focus on them. Wait and check again later.
- */
- if (!mZoomControls.hasFocus()) {
- mZoomControls.hide();
- } else {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- }
- }
- };
- }
- return mZoomControls;
- }
-
- /**
- * @hide pending API council? Assuming we make ZoomRingController itself
- * public, which I think we will.
- */
- public ZoomRingController getZoomRingController() {
- return mZoomRingController;
- }
-
- /**
- * Perform zoom in in the webview
- * @return TRUE if zoom in succeeds. FALSE if no zoom changes.
- */
- public boolean zoomIn() {
- // TODO: alternatively we can disallow this during draw history mode
- switchOutDrawHistory();
- return zoomWithPreview(mActualScale * 1.25f);
- }
-
- /**
- * Perform zoom out in the webview
- * @return TRUE if zoom out succeeds. FALSE if no zoom changes.
- */
- public boolean zoomOut() {
- // TODO: alternatively we can disallow this during draw history mode
- switchOutDrawHistory();
- return zoomWithPreview(mActualScale * 0.8f);
- }
-
- private ExtendedZoomControls createZoomControls() {
- ExtendedZoomControls zoomControls = new ExtendedZoomControls(mContext
- , null);
- zoomControls.setOnZoomInClickListener(new OnClickListener() {
- public void onClick(View v) {
- // reset time out
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- zoomIn();
- }
- });
- zoomControls.setOnZoomOutClickListener(new OnClickListener() {
- public void onClick(View v) {
- // reset time out
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- zoomOut();
- }
- });
- zoomControls.setOnZoomMagnifyClickListener(new OnClickListener() {
- public void onClick(View v) {
- // Hide the zoom ring
- mZoomRingController.setVisible(false);
-
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
- zoomScrollOut();
- }
- });
- return zoomControls;
- }
-
- private void updateSelection() {
- if (mNativeClass == 0) {
- return;
- }
- // mLastTouchX and mLastTouchY are the point in the current viewport
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- int contentSize = ViewConfiguration.getTouchSlop();
- Rect rect = new Rect(contentX - contentSize, contentY - contentSize,
- contentX + contentSize, contentY + contentSize);
- // If we were already focused on a textfield, update its cache.
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
- nativeSelectBestAt(rect);
- }
-
- /*package*/ void shortPressOnTextField() {
- if (inEditingMode()) {
- View v = mTextEntry;
- int x = viewToContent((v.getLeft() + v.getRight()) >> 1);
- int y = viewToContent((v.getTop() + v.getBottom()) >> 1);
- int contentSize = ViewConfiguration.get(getContext()).getScaledTouchSlop();
- nativeMotionUp(x, y, contentSize, true);
- }
- }
-
- private void doShortPress() {
- if (mNativeClass == 0) {
- return;
- }
- switchOutDrawHistory();
- // mLastTouchX and mLastTouchY are the point in the current viewport
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- int contentSize = ViewConfiguration.get(getContext()).getScaledTouchSlop();
- if (nativeMotionUp(contentX, contentY, contentSize, true)) {
- if (mLogEvent) {
- Checkin.updateStats(mContext.getContentResolver(),
- Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0);
- }
- }
- if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField
- && !mFocusNode.mIsTextArea) {
- playSoundEffect(SoundEffectConstants.CLICK);
- }
- }
-
- // Called by JNI to handle a touch on a node representing an email address,
- // address, or phone number
- private void overrideLoading(String url) {
- mCallbackProxy.uiOverrideUrlLoading(url);
- }
-
- @Override
- public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
- boolean result = false;
- if (inEditingMode()) {
- result = mTextEntry.requestFocus(direction, previouslyFocusedRect);
- } else {
- result = super.requestFocus(direction, previouslyFocusedRect);
- if (mWebViewCore.getSettings().getNeedInitialFocus()) {
- // For cases such as GMail, where we gain focus from a direction,
- // we want to move to the first available link.
- // FIXME: If there are no visible links, we may not want to
- int fakeKeyDirection = 0;
- switch(direction) {
- case View.FOCUS_UP:
- fakeKeyDirection = KeyEvent.KEYCODE_DPAD_UP;
- break;
- case View.FOCUS_DOWN:
- fakeKeyDirection = KeyEvent.KEYCODE_DPAD_DOWN;
- break;
- case View.FOCUS_LEFT:
- fakeKeyDirection = KeyEvent.KEYCODE_DPAD_LEFT;
- break;
- case View.FOCUS_RIGHT:
- fakeKeyDirection = KeyEvent.KEYCODE_DPAD_RIGHT;
- break;
- default:
- return result;
- }
- if (mNativeClass != 0 && !nativeUpdateFocusNode()) {
- navHandledKey(fakeKeyDirection, 1, true, 0);
- }
- }
- }
- return result;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-
- int measuredHeight = heightSize;
- int measuredWidth = widthSize;
-
- // Grab the content size from WebViewCore.
- int contentHeight = mContentHeight;
- int contentWidth = mContentWidth;
-
-// Log.d(LOGTAG, "------- measure " + heightMode);
-
- if (heightMode != MeasureSpec.EXACTLY) {
- mHeightCanMeasure = true;
- measuredHeight = contentHeight;
- if (heightMode == MeasureSpec.AT_MOST) {
- // If we are larger than the AT_MOST height, then our height can
- // no longer be measured and we should scroll internally.
- if (measuredHeight > heightSize) {
- measuredHeight = heightSize;
- mHeightCanMeasure = false;
- }
- }
- } else {
- mHeightCanMeasure = false;
- }
- if (mNativeClass != 0) {
- nativeSetHeightCanMeasure(mHeightCanMeasure);
- }
- // For the width, always use the given size unless unspecified.
- if (widthMode == MeasureSpec.UNSPECIFIED) {
- mWidthCanMeasure = true;
- measuredWidth = contentWidth;
- } else {
- mWidthCanMeasure = false;
- }
-
- synchronized (this) {
- setMeasuredDimension(measuredWidth, measuredHeight);
- }
- }
-
- @Override
- public boolean requestChildRectangleOnScreen(View child,
- Rect rect,
- boolean immediate) {
- rect.offset(child.getLeft() - child.getScrollX(),
- child.getTop() - child.getScrollY());
-
- int height = getHeight() - getHorizontalScrollbarHeight();
- int screenTop = mScrollY;
- int screenBottom = screenTop + height;
-
- int scrollYDelta = 0;
-
- if (rect.bottom > screenBottom && rect.top > screenTop) {
- if (rect.height() > height) {
- scrollYDelta += (rect.top - screenTop);
- } else {
- scrollYDelta += (rect.bottom - screenBottom);
- }
- } else if (rect.top < screenTop) {
- scrollYDelta -= (screenTop - rect.top);
- }
-
- int width = getWidth() - getVerticalScrollbarWidth();
- int screenLeft = mScrollX;
- int screenRight = screenLeft + width;
-
- int scrollXDelta = 0;
-
- if (rect.right > screenRight && rect.left > screenLeft) {
- if (rect.width() > width) {
- scrollXDelta += (rect.left - screenLeft);
- } else {
- scrollXDelta += (rect.right - screenRight);
- }
- } else if (rect.left < screenLeft) {
- scrollXDelta -= (screenLeft - rect.left);
- }
-
- if ((scrollYDelta | scrollXDelta) != 0) {
- return pinScrollBy(scrollXDelta, scrollYDelta, !immediate, 0);
- }
-
- return false;
- }
-
- /* package */ void replaceTextfieldText(int oldStart, int oldEnd,
- String replace, int newStart, int newEnd) {
- HashMap arg = new HashMap();
- arg.put("focusData", new WebViewCore.FocusData(mFocusData));
- arg.put("replace", replace);
- arg.put("start", new Integer(newStart));
- arg.put("end", new Integer(newEnd));
- mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
- }
-
- /* package */ void passToJavaScript(String currentText, KeyEvent event) {
- HashMap arg = new HashMap();
- arg.put("focusData", new WebViewCore.FocusData(mFocusData));
- arg.put("event", event);
- arg.put("currentText", currentText);
- // Increase our text generation number, and pass it to webcore thread
- mTextGeneration++;
- mWebViewCore.sendMessage(EventHub.PASS_TO_JS, mTextGeneration, 0, arg);
- // WebKit's document state is not saved until about to leave the page.
- // To make sure the host application, like Browser, has the up to date
- // document state when it goes to background, we force to save the
- // document state.
- mWebViewCore.removeMessages(EventHub.SAVE_DOCUMENT_STATE);
- mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE,
- new WebViewCore.FocusData(mFocusData), 1000);
- }
-
- /* package */ WebViewCore getWebViewCore() {
- return mWebViewCore;
- }
-
- //-------------------------------------------------------------------------
- // Methods can be called from a separate thread, like WebViewCore
- // If it needs to call the View system, it has to send message.
- //-------------------------------------------------------------------------
-
- /**
- * General handler to receive message coming from webkit thread
- */
- class PrivateHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
- > INVAL_RECT_MSG_ID ? Integer.toString(msg.what)
- : HandlerDebugString[msg.what - REMEMBER_PASSWORD]);
- }
- switch (msg.what) {
- case REMEMBER_PASSWORD: {
- mDatabase.setUsernamePassword(
- msg.getData().getString("host"),
- msg.getData().getString("username"),
- msg.getData().getString("password"));
- ((Message) msg.obj).sendToTarget();
- break;
- }
- case NEVER_REMEMBER_PASSWORD: {
- mDatabase.setUsernamePassword(
- msg.getData().getString("host"), null, null);
- ((Message) msg.obj).sendToTarget();
- break;
- }
- case SWITCH_TO_SHORTPRESS: {
- if (mTouchMode == TOUCH_INIT_MODE) {
- mTouchMode = TOUCH_SHORTPRESS_START_MODE;
- updateSelection();
- }
- break;
- }
- case SWITCH_TO_LONGPRESS: {
- mTouchMode = TOUCH_DONE_MODE;
- performLongClick();
- updateTextEntry();
- break;
- }
- case RELEASE_SINGLE_TAP: {
- mTouchMode = TOUCH_DONE_MODE;
- if ((Boolean)msg.obj) {
- doShortPress();
- }
- break;
- }
- case SWITCH_TO_ENTER:
- if (LOGV_ENABLED) Log.v(LOGTAG, "SWITCH_TO_ENTER");
- mTouchMode = TOUCH_DONE_MODE;
- onKeyUp(KeyEvent.KEYCODE_ENTER
- , new KeyEvent(KeyEvent.ACTION_UP
- , KeyEvent.KEYCODE_ENTER));
- break;
- case SCROLL_BY_MSG_ID:
- setContentScrollBy(msg.arg1, msg.arg2, (Boolean) msg.obj);
- break;
- case SYNC_SCROLL_TO_MSG_ID:
- if (mUserScroll) {
- // if user has scrolled explicitly, don't sync the
- // scroll position any more
- mUserScroll = false;
- break;
- }
- // fall through
- case SCROLL_TO_MSG_ID:
- if (setContentScrollTo(msg.arg1, msg.arg2)) {
- // if we can't scroll to the exact position due to pin,
- // send a message to WebCore to re-scroll when we get a
- // new picture
- mUserScroll = false;
- mWebViewCore.sendMessage(EventHub.SYNC_SCROLL,
- msg.arg1, msg.arg2);
- }
- break;
- case SPAWN_SCROLL_TO_MSG_ID:
- spawnContentScrollTo(msg.arg1, msg.arg2);
- break;
- case NEW_PICTURE_MSG_ID:
- // called for new content
- final WebViewCore.DrawData draw =
- (WebViewCore.DrawData) msg.obj;
- final Point viewSize = draw.mViewPoint;
- if (mZoomScale > 0) {
- // use the same logic in sendViewSizeZoom() to make sure
- // the mZoomScale has matched the viewSize so that we
- // can clear mZoomScale
- if (Math.round(getViewWidth() / mZoomScale) == viewSize.x) {
- mZoomScale = 0;
- mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR,
- 0, 0);
- }
- }
- mMinContentWidth = msg.arg1;
- if (mMinContentWidth > MAX_FLOAT_CONTENT_WIDTH) {
- mMinZoomScale = (float) getViewWidth()
- / draw.mWidthHeight.x;
- }
- // We update the layout (i.e. request a layout from the
- // view system) if the last view size that we sent to
- // WebCore matches the view size of the picture we just
- // received in the fixed dimension.
- final boolean updateLayout = viewSize.x == mLastWidthSent
- && viewSize.y == mLastHeightSent;
- recordNewContentSize(draw.mWidthHeight.x,
- draw.mWidthHeight.y, updateLayout);
- if (LOGV_ENABLED) {
- Rect b = draw.mInvalRegion.getBounds();
- Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
- b.left+","+b.top+","+b.right+","+b.bottom+"}");
- }
- invalidate(contentToView(draw.mInvalRegion.getBounds()));
- if (mPictureListener != null) {
- mPictureListener.onNewPicture(WebView.this, capturePicture());
- }
- break;
- case WEBCORE_INITIALIZED_MSG_ID:
- // nativeCreate sets mNativeClass to a non-zero value
- nativeCreate(msg.arg1);
- break;
- case UPDATE_TEXTFIELD_TEXT_MSG_ID:
- // Make sure that the textfield is currently focused
- // and representing the same node as the pointer.
- if (inEditingMode() &&
- mTextEntry.isSameTextField(msg.arg1)) {
- if (msg.getData().getBoolean("password")) {
- Spannable text = (Spannable) mTextEntry.getText();
- int start = Selection.getSelectionStart(text);
- int end = Selection.getSelectionEnd(text);
- mTextEntry.setInPassword(true);
- // Restore the selection, which may have been
- // ruined by setInPassword.
- Spannable pword = (Spannable) mTextEntry.getText();
- Selection.setSelection(pword, start, end);
- // If the text entry has created more events, ignore
- // this one.
- } else if (msg.arg2 == mTextGeneration) {
- mTextEntry.setTextAndKeepSelection(
- (String) msg.obj);
- }
- }
- break;
- case DID_FIRST_LAYOUT_MSG_ID:
- if (mNativeClass == 0) {
- break;
- }
-// Do not reset the focus or clear the text; the user may have already
-// navigated or entered text at this point. The focus should have gotten
-// reset, if need be, when the focus cache was built. Similarly, the text
-// view should already be torn down and rebuilt if needed.
-// nativeResetFocus();
-// clearTextEntry();
- HashMap scaleLimit = (HashMap) msg.obj;
- int minScale = (Integer) scaleLimit.get("minScale");
- if (minScale == 0) {
- mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
- } else {
- mMinZoomScale = (float) (minScale / 100.0);
- }
- int maxScale = (Integer) scaleLimit.get("maxScale");
- if (maxScale == 0) {
- mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
- } else {
- mMaxZoomScale = (float) (maxScale / 100.0);
- }
- // If history Picture is drawn, don't update zoomWidth
- if (mDrawHistory) {
- break;
- }
- int width = getViewWidth();
- if (width == 0) {
- break;
- }
- int initialScale = msg.arg1;
- int viewportWidth = msg.arg2;
- // by default starting a new page with 100% zoom scale.
- float scale = 1.0f;
- if (mInitialScale > 0) {
- scale = mInitialScale / 100.0f;
- } else {
- if (mWebViewCore.getSettings().getUseWideViewPort()) {
- // force viewSizeChanged by setting mLastWidthSent
- // to 0
- mLastWidthSent = 0;
- }
- if (initialScale == 0) {
- // if viewportWidth is defined and it is smaller
- // than the view width, zoom in to fill the view
- if (viewportWidth > 0 && viewportWidth < width) {
- scale = (float) width / viewportWidth;
- }
- } else {
- scale = initialScale / 100.0f;
- }
- }
- setNewZoomScale(scale, false);
- break;
- case MARK_NODE_INVALID_ID:
- nativeMarkNodeInvalid(msg.arg1);
- break;
- case NOTIFY_FOCUS_SET_MSG_ID:
- if (mNativeClass != 0) {
- nativeNotifyFocusSet(inEditingMode());
- }
- break;
- case UPDATE_TEXT_ENTRY_MSG_ID:
- // this is sent after finishing resize in WebViewCore. Make
- // sure the text edit box is still on the screen.
- boolean alreadyThere = inEditingMode();
- if (alreadyThere && nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (node.mIsTextField || node.mIsTextArea) {
- mTextEntry.bringIntoView();
- }
- }
- updateTextEntry();
- break;
- case RECOMPUTE_FOCUS_MSG_ID:
- if (mNativeClass != 0) {
- nativeRecomputeFocus();
- }
- break;
- case INVAL_RECT_MSG_ID: {
- Rect r = (Rect)msg.obj;
- if (r == null) {
- invalidate();
- } else {
- // we need to scale r from content into view coords,
- // which viewInvalidate() does for us
- viewInvalidate(r.left, r.top, r.right, r.bottom);
- }
- break;
- }
- case UPDATE_TEXT_ENTRY_ADAPTER:
- HashMap data = (HashMap) msg.obj;
- if (mTextEntry.isSameTextField(msg.arg1)) {
- AutoCompleteAdapter adapter =
- (AutoCompleteAdapter) data.get("adapter");
- mTextEntry.setAdapterCustom(adapter);
- }
- break;
- case UPDATE_CLIPBOARD:
- String str = (String) msg.obj;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "UPDATE_CLIPBOARD " + str);
- }
- try {
- IClipboard clip = IClipboard.Stub.asInterface(
- ServiceManager.getService("clipboard"));
- clip.setClipboardText(str);
- } catch (android.os.RemoteException e) {
- Log.e(LOGTAG, "Clipboard failed", e);
- }
- break;
- case RESUME_WEBCORE_UPDATE:
- WebViewCore.resumeUpdate(mWebViewCore);
- break;
-
- case LONG_PRESS_ENTER:
- // as this is shared by keydown and trackballdown, reset all
- // the states
- mGotEnterDown = false;
- mTrackballDown = false;
- // LONG_PRESS_ENTER is sent as a delayed message. If we
- // switch to windows overview, the WebView will be
- // temporarily removed from the view system. In that case,
- // do nothing.
- if (getParent() != null) {
- performLongClick();
- }
- break;
-
- case WEBCORE_NEED_TOUCH_EVENTS:
- mForwardTouchEvents = (msg.arg1 != 0);
- break;
-
- case PREVENT_TOUCH_ID:
- if (msg.arg1 == MotionEvent.ACTION_DOWN) {
- mPreventDrag = msg.arg2 == 1;
- if (mPreventDrag) {
- mTouchMode = TOUCH_DONE_MODE;
- }
- }
- break;
-
- case DISMISS_ZOOM_RING_TUTORIAL:
- mZoomRingController.finishZoomTutorial();
- break;
-
- default:
- super.handleMessage(msg);
- break;
- }
- }
- }
-
- // Class used to use a dropdown for a <select> element
- private class InvokeListBox implements Runnable {
- // Strings for the labels in the listbox.
- private String[] mArray;
- // Array representing whether each item is enabled.
- private boolean[] mEnableArray;
- // Whether the listbox allows multiple selection.
- private boolean mMultiple;
- // Passed in to a list with multiple selection to tell
- // which items are selected.
- private int[] mSelectedArray;
- // Passed in to a list with single selection to tell
- // where the initial selection is.
- private int mSelection;
-
- private Container[] mContainers;
-
- // Need these to provide stable ids to my ArrayAdapter,
- // which normally does not have stable ids. (Bug 1250098)
- private class Container extends Object {
- String mString;
- boolean mEnabled;
- int mId;
-
- public String toString() {
- return mString;
- }
- }
-
- /**
- * Subclass ArrayAdapter so we can disable OptionGroupLabels,
- * and allow filtering.
- */
- private class MyArrayListAdapter extends ArrayAdapter<Container> {
- public MyArrayListAdapter(Context context, Container[] objects, boolean multiple) {
- super(context,
- multiple ? com.android.internal.R.layout.select_dialog_multichoice :
- com.android.internal.R.layout.select_dialog_singlechoice,
- objects);
- }
-
- @Override
- public boolean hasStableIds() {
- return true;
- }
-
- private Container item(int position) {
- if (position < 0 || position >= getCount()) {
- return null;
- }
- return (Container) getItem(position);
- }
-
- @Override
- public long getItemId(int position) {
- Container item = item(position);
- if (item == null) {
- return -1;
- }
- return item.mId;
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- @Override
- public boolean isEnabled(int position) {
- Container item = item(position);
- if (item == null) {
- return false;
- }
- return item.mEnabled;
- }
- }
-
- private InvokeListBox(String[] array,
- boolean[] enabled, int[] selected) {
- mMultiple = true;
- mSelectedArray = selected;
-
- int length = array.length;
- mContainers = new Container[length];
- for (int i = 0; i < length; i++) {
- mContainers[i] = new Container();
- mContainers[i].mString = array[i];
- mContainers[i].mEnabled = enabled[i];
- mContainers[i].mId = i;
- }
- }
-
- private InvokeListBox(String[] array, boolean[] enabled, int
- selection) {
- mSelection = selection;
- mMultiple = false;
-
- int length = array.length;
- mContainers = new Container[length];
- for (int i = 0; i < length; i++) {
- mContainers[i] = new Container();
- mContainers[i].mString = array[i];
- mContainers[i].mEnabled = enabled[i];
- mContainers[i].mId = i;
- }
- }
-
- public void run() {
- final ListView listView = (ListView) LayoutInflater.from(mContext)
- .inflate(com.android.internal.R.layout.select_dialog, null);
- final MyArrayListAdapter adapter = new
- MyArrayListAdapter(mContext, mContainers, mMultiple);
- AlertDialog.Builder b = new AlertDialog.Builder(mContext)
- .setView(listView).setCancelable(true)
- .setInverseBackgroundForced(true);
-
- if (mMultiple) {
- b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- mWebViewCore.sendMessage(
- EventHub.LISTBOX_CHOICES,
- adapter.getCount(), 0,
- listView.getCheckedItemPositions());
- }});
- b.setNegativeButton(android.R.string.cancel, null);
- }
- final AlertDialog dialog = b.create();
- listView.setAdapter(adapter);
- listView.setFocusableInTouchMode(true);
- // There is a bug (1250103) where the checks in a ListView with
- // multiple items selected are associated with the positions, not
- // the ids, so the items do not properly retain their checks when
- // filtered. Do not allow filtering on multiple lists until
- // that bug is fixed.
-
- // Disable filter altogether
- // listView.setTextFilterEnabled(!mMultiple);
- if (mMultiple) {
- listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- int length = mSelectedArray.length;
- for (int i = 0; i < length; i++) {
- listView.setItemChecked(mSelectedArray[i], true);
- }
- } else {
- listView.setOnItemClickListener(new OnItemClickListener() {
- public void onItemClick(AdapterView parent, View v,
- int position, long id) {
- mWebViewCore.sendMessage(
- EventHub.SINGLE_LISTBOX_CHOICE, (int)id, 0);
- dialog.dismiss();
- }
- });
- if (mSelection != -1) {
- listView.setSelection(mSelection);
- listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- listView.setItemChecked(mSelection, true);
- }
- }
- dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- mWebViewCore.sendMessage(
- EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
- }
- });
- dialog.show();
- }
- }
-
- /*
- * Request a dropdown menu for a listbox with multiple selection.
- *
- * @param array Labels for the listbox.
- * @param enabledArray Which positions are enabled.
- * @param selectedArray Which positions are initally selected.
- */
- void requestListBox(String[] array, boolean[]enabledArray, int[]
- selectedArray) {
- mPrivateHandler.post(
- new InvokeListBox(array, enabledArray, selectedArray));
- }
-
- /*
- * Request a dropdown menu for a listbox with single selection or a single
- * <select> element.
- *
- * @param array Labels for the listbox.
- * @param enabledArray Which positions are enabled.
- * @param selection Which position is initally selected.
- */
- void requestListBox(String[] array, boolean[]enabledArray, int selection) {
- mPrivateHandler.post(
- new InvokeListBox(array, enabledArray, selection));
- }
-
- // called by JNI
- private void sendFinalFocus(int frame, int node, int x, int y) {
- WebViewCore.FocusData focusData = new WebViewCore.FocusData();
- focusData.mFrame = frame;
- focusData.mNode = node;
- focusData.mX = x;
- focusData.mY = y;
- mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
- EventHub.NO_FOCUS_CHANGE_BLOCK, 0, focusData);
- }
-
- // called by JNI
- private void setFocusData(int moveGeneration, int buildGeneration,
- int frame, int node, int x, int y, boolean ignoreNullFocus) {
- mFocusData.mMoveGeneration = moveGeneration;
- mFocusData.mBuildGeneration = buildGeneration;
- mFocusData.mFrame = frame;
- mFocusData.mNode = node;
- mFocusData.mX = x;
- mFocusData.mY = y;
- mFocusData.mIgnoreNullFocus = ignoreNullFocus;
- }
-
- // called by JNI
- private void sendKitFocus() {
- WebViewCore.FocusData focusData = new WebViewCore.FocusData(mFocusData);
- mWebViewCore.sendMessage(EventHub.SET_KIT_FOCUS, focusData);
- }
-
- // called by JNI
- private void sendMotionUp(int touchGeneration, int buildGeneration,
- int frame, int node, int x, int y, int size, boolean isClick,
- boolean retry) {
- WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
- touchUpData.mMoveGeneration = touchGeneration;
- touchUpData.mBuildGeneration = buildGeneration;
- touchUpData.mSize = size;
- touchUpData.mIsClick = isClick;
- touchUpData.mRetry = retry;
- mFocusData.mFrame = touchUpData.mFrame = frame;
- mFocusData.mNode = touchUpData.mNode = node;
- mFocusData.mX = touchUpData.mX = x;
- mFocusData.mY = touchUpData.mY = y;
- mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
- }
-
-
- private int getScaledMaxXScroll() {
- int width;
- if (mHeightCanMeasure == false) {
- width = getViewWidth() / 4;
- } else {
- Rect visRect = new Rect();
- calcOurVisibleRect(visRect);
- width = visRect.width() / 2;
- }
- // FIXME the divisor should be retrieved from somewhere
- return viewToContent(width);
- }
-
- private int getScaledMaxYScroll() {
- int height;
- if (mHeightCanMeasure == false) {
- height = getViewHeight() / 4;
- } else {
- Rect visRect = new Rect();
- calcOurVisibleRect(visRect);
- height = visRect.height() / 2;
- }
- // FIXME the divisor should be retrieved from somewhere
- // the closest thing today is hard-coded into ScrollView.java
- // (from ScrollView.java, line 363) int maxJump = height/2;
- return viewToContent(height);
- }
-
- /**
- * Called by JNI to invalidate view
- */
- private void viewInvalidate() {
- invalidate();
- }
-
- // return true if the key was handled
- private boolean navHandledKey(int keyCode, int count, boolean noScroll
- , long time) {
- if (mNativeClass == 0) {
- return false;
- }
- mLastFocusTime = time;
- mLastFocusBounds = nativeGetFocusRingBounds();
- boolean keyHandled = nativeMoveFocus(keyCode, count, noScroll) == false;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "navHandledKey mLastFocusBounds=" + mLastFocusBounds
- + " mLastFocusTime=" + mLastFocusTime
- + " handled=" + keyHandled);
- }
- if (keyHandled == false || mHeightCanMeasure == false) {
- return keyHandled;
- }
- Rect contentFocus = nativeGetFocusRingBounds();
- if (contentFocus.isEmpty()) return keyHandled;
- Rect viewFocus = contentToView(contentFocus);
- Rect visRect = new Rect();
- calcOurVisibleRect(visRect);
- Rect outset = new Rect(visRect);
- int maxXScroll = visRect.width() / 2;
- int maxYScroll = visRect.height() / 2;
- outset.inset(-maxXScroll, -maxYScroll);
- if (Rect.intersects(outset, viewFocus) == false) {
- return keyHandled;
- }
- // FIXME: Necessary because ScrollView/ListView do not scroll left/right
- int maxH = Math.min(viewFocus.right - visRect.right, maxXScroll);
- if (maxH > 0) {
- pinScrollBy(maxH, 0, true, 0);
- } else {
- maxH = Math.max(viewFocus.left - visRect.left, -maxXScroll);
- if (maxH < 0) {
- pinScrollBy(maxH, 0, true, 0);
- }
- }
- if (mLastFocusBounds.isEmpty()) return keyHandled;
- if (mLastFocusBounds.equals(contentFocus)) return keyHandled;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "navHandledKey contentFocus=" + contentFocus);
- }
- requestRectangleOnScreen(viewFocus);
- mUserScroll = true;
- return keyHandled;
- }
-
- /**
- * Set the background color. It's white by default. Pass
- * zero to make the view transparent.
- * @param color the ARGB color described by Color.java
- */
- public void setBackgroundColor(int color) {
- mBackgroundColor = color;
- mWebViewCore.sendMessage(EventHub.SET_BACKGROUND_COLOR, color);
- }
-
- public void debugDump() {
- nativeDebugDump();
- mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
- }
-
- /**
- * Update our cache with updatedText.
- * @param updatedText The new text to put in our cache.
- */
- /* package */ void updateCachedTextfield(String updatedText) {
- // Also place our generation number so that when we look at the cache
- // we recognize that it is up to date.
- nativeUpdateCachedTextfield(updatedText, mTextGeneration);
- }
-
- // Never call this version except by updateCachedTextfield(String) -
- // we always want to pass in our generation number.
- private native void nativeUpdateCachedTextfield(String updatedText,
- int generation);
- private native void nativeClearFocus(int x, int y);
- private native void nativeCreate(int ptr);
- private native void nativeDebugDump();
- private native void nativeDestroy();
- private native void nativeDrawFocusRing(Canvas content);
- private native void nativeDrawSelection(Canvas content
- , int x, int y, boolean extendSelection);
- private native void nativeDrawSelectionRegion(Canvas content);
- private native boolean nativeUpdateFocusNode();
- private native Rect nativeGetFocusRingBounds();
- private native Rect nativeGetNavBounds();
- private native void nativeInstrumentReport();
- private native void nativeMarkNodeInvalid(int node);
- // return true if the page has been scrolled
- private native boolean nativeMotionUp(int x, int y, int slop, boolean isClick);
- // returns false if it handled the key
- private native boolean nativeMoveFocus(int keyCode, int count,
- boolean noScroll);
- private native void nativeNotifyFocusSet(boolean inEditingMode);
- private native void nativeRecomputeFocus();
- // Like many other of our native methods, you must make sure that
- // mNativeClass is not null before calling this method.
- private native void nativeRecordButtons(boolean focused,
- boolean pressed, boolean invalidate);
- private native void nativeResetFocus();
- private native void nativeResetNavClipBounds();
- private native void nativeSelectBestAt(Rect rect);
- private native void nativeSetFindIsDown();
- private native void nativeSetFollowedLink(boolean followed);
- private native void nativeSetHeightCanMeasure(boolean measure);
- private native void nativeSetNavBounds(Rect rect);
- private native void nativeSetNavClipBounds(Rect rect);
- private native String nativeImageURI(int x, int y);
- /**
- * Returns true if the native focus nodes says it wants to handle key events
- * (ala plugins). This can only be called if mNativeClass is non-zero!
- */
- private native boolean nativeFocusNodeWantsKeyEvents();
- private native void nativeMoveSelection(int x, int y
- , boolean extendSelection);
- private native Region nativeGetSelection();
-
- private native void nativeDumpDisplayTree(String urlOrNull);
-}
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
deleted file mode 100644
index a185779..0000000
--- a/core/java/android/webkit/WebViewClient.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2008 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.graphics.Bitmap;
-import android.net.http.SslError;
-import android.os.Message;
-import android.view.KeyEvent;
-
-public class WebViewClient {
-
- /**
- * Give the host application a chance to take over the control when a new
- * url is about to be loaded in the current WebView. If WebViewClient is not
- * provided, by default WebView will ask Activity Manager to choose the
- * proper handler for the url. If WebViewClient is provided, return true
- * means the host application handles the url, while return false means the
- * current WebView handles the url.
- *
- * @param view The WebView that is initiating the callback.
- * @param url The url to be loaded.
- * @return True if the host application wants to leave the current WebView
- * and handle the url itself, otherwise return false.
- */
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- return false;
- }
-
- /**
- * Notify the host application that a page has started loading. This method
- * is called once for each main frame load so a page with iframes or
- * framesets will call onPageStarted one time for the main frame. This also
- * means that onPageStarted will not be called when the contents of an
- * embedded frame changes, i.e. clicking a link whose target is an iframe.
- *
- * @param view The WebView that is initiating the callback.
- * @param url The url to be loaded.
- * @param favicon The favicon for this page if it already exists in the
- * database.
- */
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- }
-
- /**
- * Notify the host application that a page has finished loading. This method
- * is called only for main frame. When onPageFinished() is called, the
- * rendering picture may not be updated yet. To get the notification for the
- * new Picture, use {@link WebView.PictureListener#onNewPicture}.
- *
- * @param view The WebView that is initiating the callback.
- * @param url The url of the page.
- */
- public void onPageFinished(WebView view, String url) {
- }
-
- /**
- * Notify the host application that the WebView will load the resource
- * specified by the given url.
- *
- * @param view The WebView that is initiating the callback.
- * @param url The url of the resource the WebView will load.
- */
- public void onLoadResource(WebView view, String url) {
- }
-
- /**
- * Notify the host application that there have been an excessive number of
- * HTTP redirects. As the host application if it would like to continue
- * trying to load the resource. The default behavior is to send the cancel
- * message.
- *
- * @param view The WebView that is initiating the callback.
- * @param cancelMsg The message to send if the host wants to cancel
- * @param continueMsg The message to send if the host wants to continue
- */
- public void onTooManyRedirects(WebView view, Message cancelMsg,
- Message continueMsg) {
- cancelMsg.sendToTarget();
- }
-
- /**
- * Report an error to an activity. These errors come up from WebCore, and
- * are network errors.
- *
- * @param view The WebView that is initiating the callback.
- * @param errorCode The HTTP error code.
- * @param description A String description.
- * @param failingUrl The url that failed.
- */
- public void onReceivedError(WebView view, int errorCode,
- String description, String failingUrl) {
- }
-
- /**
- * As the host application if the browser should resend data as the
- * requested page was a result of a POST. The default is to not resend the
- * data.
- *
- * @param view The WebView that is initiating the callback.
- * @param dontResend The message to send if the browser should not resend
- * @param resend The message to send if the browser should resend data
- */
- public void onFormResubmission(WebView view, Message dontResend,
- Message resend) {
- dontResend.sendToTarget();
- }
-
- /**
- * Notify the host application to update its visited links database.
- *
- * @param view The WebView that is initiating the callback.
- * @param url The url being visited.
- * @param isReload True if this url is being reloaded.
- */
- public void doUpdateVisitedHistory(WebView view, String url,
- boolean isReload) {
- }
-
- /**
- * Notify the host application to handle a ssl certificate error request
- * (display the error to the user and ask whether to proceed or not). The
- * host application has to call either handler.cancel() or handler.proceed()
- * as the connection is suspended and waiting for the response. The default
- * behavior is to cancel the load.
- *
- * @param view The WebView that is initiating the callback.
- * @param handler An SslErrorHandler object that will handle the user's
- * response.
- * @param error The SSL error object.
- * @hide - hide this because it contains a parameter of type SslError,
- * which is located in a hidden package.
- */
- public void onReceivedSslError(WebView view, SslErrorHandler handler,
- SslError error) {
- handler.cancel();
- }
-
- /**
- * Notify the host application to handle an authentication request. The
- * default behavior is to cancel the request.
- *
- * @param view The WebView that is initiating the callback.
- * @param handler The HttpAuthHandler that will handle the user's response.
- * @param host The host requiring authentication.
- * @param realm A description to help store user credentials for future
- * visits.
- */
- public void onReceivedHttpAuthRequest(WebView view,
- HttpAuthHandler handler, String host, String realm) {
- handler.cancel();
- }
-
- /**
- * Give the host application a chance to handle the key event synchronously.
- * e.g. menu shortcut key events need to be filtered this way. If return
- * true, WebView will not handle the key event. If return false, WebView
- * will always handle the key event, so none of the super in the view chain
- * will see the key event. The default behavior returns false.
- *
- * @param view The WebView that is initiating the callback.
- * @param event The key event.
- * @return True if the host application wants to handle the key event
- * itself, otherwise return false
- */
- public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
- return false;
- }
-
- /**
- * Notify the host application that a key was not handled by the WebView.
- * Except system keys, WebView always consumes the keys in the normal flow
- * or if shouldOverrideKeyEvent returns true. This is called asynchronously
- * from where the key is dispatched. It gives the host application an chance
- * to handle the unhandled key events.
- *
- * @param view The WebView that is initiating the callback.
- * @param event The key event.
- */
- public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
- }
-
- /**
- * Notify the host application that the scale applied to the WebView has
- * changed.
- *
- * @param view he WebView that is initiating the callback.
- * @param oldScale The old scale factor
- * @param newScale The new scale factor
- */
- public void onScaleChanged(WebView view, float oldScale, float newScale) {
- }
-}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
deleted file mode 100644
index a7261c5..0000000
--- a/core/java/android/webkit/WebViewCore.java
+++ /dev/null
@@ -1,1672 +0,0 @@
-/*
- * Copyright (C) 2007 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.content.Context;
-import android.graphics.Canvas;
-import android.graphics.DrawFilter;
-import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.Picture;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.util.Config;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.view.KeyEvent;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import junit.framework.Assert;
-
-final class WebViewCore {
-
- private static final String LOGTAG = "webcore";
- static final boolean DEBUG = false;
- static final boolean LOGV_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
-
- static {
- // Load libwebcore during static initialization. This happens in the
- // zygote process so it will be shared read-only across all app
- // processes.
- System.loadLibrary("webcore");
- }
-
- /*
- * WebViewCore always executes in the same thread as the native webkit.
- */
-
- // The WebView that corresponds to this WebViewCore.
- private WebView mWebView;
- // Proxy for handling callbacks from native code
- private final CallbackProxy mCallbackProxy;
- // Settings object for maintaining all settings
- private final WebSettings mSettings;
- // Context for initializing the BrowserFrame with the proper assets.
- private final Context mContext;
- // The pointer to a native view object.
- private int mNativeClass;
- // The BrowserFrame is an interface to the native Frame component.
- private BrowserFrame mBrowserFrame;
-
- /*
- * range is from 200 to 10,000. 0 is a special value means device-width. -1
- * means undefined.
- */
- private int mViewportWidth = -1;
-
- /*
- * range is from 200 to 10,000. 0 is a special value means device-height. -1
- * means undefined.
- */
- private int mViewportHeight = -1;
-
- /*
- * scale in percent, range is from 1 to 1000. 0 means undefined.
- */
- private int mViewportInitialScale = 0;
-
- /*
- * scale in percent, range is from 1 to 1000. 0 means undefined.
- */
- private int mViewportMinimumScale = 0;
-
- /*
- * scale in percent, range is from 1 to 1000. 0 means undefined.
- */
- private int mViewportMaximumScale = 0;
-
- private boolean mViewportUserScalable = true;
-
- private int mRestoredScale = 100;
- private int mRestoredX = 0;
- private int mRestoredY = 0;
-
- private int mWebkitScrollX = 0;
- private int mWebkitScrollY = 0;
-
- // The thread name used to identify the WebCore thread and for use in
- // debugging other classes that require operation within the WebCore thread.
- /* package */ static final String THREAD_NAME = "WebViewCoreThread";
-
- public WebViewCore(Context context, WebView w, CallbackProxy proxy) {
- // No need to assign this in the WebCore thread.
- mCallbackProxy = proxy;
- mWebView = w;
- // This context object is used to initialize the WebViewCore during
- // subwindow creation.
- mContext = context;
-
- // We need to wait for the initial thread creation before sending
- // a message to the WebCore thread.
- // XXX: This is the only time the UI thread will wait for the WebCore
- // thread!
- synchronized (WebViewCore.class) {
- if (sWebCoreHandler == null) {
- // Create a global thread and start it.
- Thread t = new Thread(new WebCoreThread());
- t.setName(THREAD_NAME);
- t.start();
- try {
- WebViewCore.class.wait();
- } catch (InterruptedException e) {
- Log.e(LOGTAG, "Caught exception while waiting for thread " +
- "creation.");
- Log.e(LOGTAG, Log.getStackTraceString(e));
- }
- }
- }
- // Create an EventHub to handle messages before and after the thread is
- // ready.
- mEventHub = new EventHub();
- // Create a WebSettings object for maintaining all settings
- mSettings = new WebSettings(mContext);
- // The WebIconDatabase needs to be initialized within the UI thread so
- // just request the instance here.
- WebIconDatabase.getInstance();
- // Send a message to initialize the WebViewCore.
- Message init = sWebCoreHandler.obtainMessage(
- WebCoreThread.INITIALIZE, this);
- sWebCoreHandler.sendMessage(init);
- }
-
- /* Initialize private data within the WebCore thread.
- */
- private void initialize() {
- /* Initialize our private BrowserFrame class to handle all
- * frame-related functions. We need to create a new view which
- * in turn creates a C level FrameView and attaches it to the frame.
- */
- mBrowserFrame = new BrowserFrame(mContext, this, mCallbackProxy,
- mSettings);
- // Sync the native settings and also create the WebCore thread handler.
- mSettings.syncSettingsAndCreateHandler(mBrowserFrame);
- // Create the handler and transfer messages for the IconDatabase
- WebIconDatabase.getInstance().createHandler();
- // The transferMessages call will transfer all pending messages to the
- // WebCore thread handler.
- mEventHub.transferMessages();
-
- // Send a message back to WebView to tell it that we have set up the
- // WebCore thread.
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.WEBCORE_INITIALIZED_MSG_ID,
- mNativeClass, 0).sendToTarget();
- }
-
- }
-
- /* Handle the initialization of WebViewCore during subwindow creation. This
- * method is called from the WebCore thread but it is called before the
- * INITIALIZE message can be handled.
- */
- /* package */ void initializeSubwindow() {
- // Go ahead and initialize the core components.
- initialize();
- // Remove the INITIALIZE method so we don't try to initialize twice.
- sWebCoreHandler.removeMessages(WebCoreThread.INITIALIZE, this);
- }
-
- /* Get the BrowserFrame component. This is used for subwindow creation and
- * is called only from BrowserFrame in the WebCore thread. */
- /* package */ BrowserFrame getBrowserFrame() {
- return mBrowserFrame;
- }
-
- //-------------------------------------------------------------------------
- // Common methods
- //-------------------------------------------------------------------------
-
- /**
- * Causes all timers to pause. This applies to all WebViews in the current
- * app process.
- */
- public static void pauseTimers() {
- if (BrowserFrame.sJavaBridge == null) {
- throw new IllegalStateException(
- "No WebView has been created in this process!");
- }
- BrowserFrame.sJavaBridge.pause();
- }
-
- /**
- * Resume all timers. This applies to all WebViews in the current process.
- */
- public static void resumeTimers() {
- if (BrowserFrame.sJavaBridge == null) {
- throw new IllegalStateException(
- "No WebView has been created in this process!");
- }
- BrowserFrame.sJavaBridge.resume();
- }
-
- public WebSettings getSettings() {
- return mSettings;
- }
-
- /**
- * Invoke a javascript alert.
- * @param message The message displayed in the alert.
- */
- protected void jsAlert(String url, String message) {
- mCallbackProxy.onJsAlert(url, message);
- }
-
- /**
- * Invoke a javascript confirm dialog.
- * @param message The message displayed in the dialog.
- * @return True if the user confirmed or false if the user cancelled.
- */
- protected boolean jsConfirm(String url, String message) {
- return mCallbackProxy.onJsConfirm(url, message);
- }
-
- /**
- * Invoke a javascript prompt dialog.
- * @param message The message to be displayed in the dialog.
- * @param defaultValue The default value in the prompt input.
- * @return The input from the user or null to indicate the user cancelled
- * the dialog.
- */
- protected String jsPrompt(String url, String message, String defaultValue) {
- return mCallbackProxy.onJsPrompt(url, message, defaultValue);
- }
-
- /**
- * Invoke a javascript before unload dialog.
- * @param url The url that is requesting the dialog.
- * @param message The message displayed in the dialog.
- * @return True if the user confirmed or false if the user cancelled. False
- * will cancel the navigation.
- */
- protected boolean jsUnload(String url, String message) {
- return mCallbackProxy.onJsBeforeUnload(url, message);
- }
-
- //-------------------------------------------------------------------------
- // JNI methods
- //-------------------------------------------------------------------------
-
- static native String nativeFindAddress(String addr);
-
- /**
- * Rebuild the nav cache if the dom changed.
- */
- private native void nativeCheckNavCache();
-
- /**
- * Empty the picture set.
- */
- private native void nativeClearContent();
-
- /**
- * Create a flat picture from the set of pictures.
- */
- private native void nativeCopyContentToPicture(Picture picture);
-
- /**
- * Draw the picture set with a background color. Returns true
- * if some individual picture took too long to draw and can be
- * split into parts. Called from the UI thread.
- */
- private native boolean nativeDrawContent(Canvas canvas, int color);
-
- /**
- * Redraw a portion of the picture set. The Point wh returns the
- * width and height of the overall picture.
- */
- private native boolean nativeRecordContent(Region invalRegion, Point wh);
-
- /**
- * Splits slow parts of the picture set. Called from the webkit
- * thread after nativeDrawContent returns true.
- */
- private native void nativeSplitContent();
-
- private native boolean nativeKey(int keyCode, int unichar,
- int repeatCount, boolean isShift, boolean isAlt, boolean isDown);
-
- private native boolean nativeClick();
-
- private native void nativeSendListBoxChoices(boolean[] choices, int size);
-
- private native void nativeSendListBoxChoice(int choice);
-
- /* Tell webkit what its width and height are, for the purposes
- of layout/line-breaking. These coordinates are in document space,
- which is the same as View coords unless we have zoomed the document
- (see nativeSetZoom).
- screenWidth is used by layout to wrap column around. If viewport uses
- fixed size, screenWidth can be different from width with zooming.
- should this be called nativeSetViewPortSize?
- */
- private native void nativeSetSize(int width, int height, int screenWidth,
- float scale, int realScreenWidth, int screenHeight);
-
- private native int nativeGetContentMinPrefWidth();
-
- // Start: functions that deal with text editing
- private native void nativeReplaceTextfieldText(int frame, int node, int x,
- int y, int oldStart, int oldEnd, String replace, int newStart,
- int newEnd);
-
- private native void passToJs(int frame, int node, int x, int y, int gen,
- String currentText, int keyCode, int keyValue, boolean down,
- boolean cap, boolean fn, boolean sym);
-
- private native void nativeSaveDocumentState(int frame);
-
- private native void nativeSetFinalFocus(int framePtr, int nodePtr, int x,
- int y, boolean block);
-
- private native void nativeSetKitFocus(int moveGeneration,
- int buildGeneration, int framePtr, int nodePtr, int x, int y,
- boolean ignoreNullFocus);
-
- private native String nativeRetrieveHref(int framePtr, int nodePtr);
-
- private native void nativeTouchUp(int touchGeneration,
- int buildGeneration, int framePtr, int nodePtr, int x, int y,
- int size, boolean isClick, boolean retry);
-
- private native boolean nativeHandleTouchEvent(int action, int x, int y);
-
- private native void nativeUnblockFocus();
-
- private native void nativeUpdateFrameCache();
-
- private native void nativeSetSnapAnchor(int x, int y);
-
- private native void nativeSnapToAnchor();
-
- private native void nativeSetBackgroundColor(int color);
-
- private native void nativeDumpDomTree(boolean useFile);
-
- private native void nativeDumpRenderTree(boolean useFile);
-
- private native void nativeDumpNavTree();
-
- private native void nativeRefreshPlugins(boolean reloadOpenPages);
-
- /**
- * Delete text from start to end in the focused textfield. If there is no
- * focus, or if start == end, silently fail. If start and end are out of
- * order, swap them.
- * @param start Beginning of selection to delete.
- * @param end End of selection to delete.
- */
- private native void nativeDeleteSelection(int frame, int node, int x, int y,
- int start, int end);
-
- /**
- * Set the selection to (start, end) in the focused textfield. If start and
- * end are out of order, swap them.
- * @param start Beginning of selection.
- * @param end End of selection.
- */
- private native void nativeSetSelection(int frame, int node, int x, int y,
- int start, int end);
-
- private native String nativeGetSelection(Region sel);
-
- // Register a scheme to be treated as local scheme so that it can access
- // local asset files for resources
- private native void nativeRegisterURLSchemeAsLocal(String scheme);
-
- // EventHub for processing messages
- private final EventHub mEventHub;
- // WebCore thread handler
- private static Handler sWebCoreHandler;
- // Class for providing Handler creation inside the WebCore thread.
- private static class WebCoreThread implements Runnable {
- // Message id for initializing a new WebViewCore.
- private static final int INITIALIZE = 0;
- private static final int REDUCE_PRIORITY = 1;
- private static final int RESUME_PRIORITY = 2;
- private static final int CACHE_TICKER = 3;
- private static final int BLOCK_CACHE_TICKER = 4;
- private static final int RESUME_CACHE_TICKER = 5;
-
- private static final int CACHE_TICKER_INTERVAL = 60 * 1000; // 1 minute
-
- private static boolean mCacheTickersBlocked = true;
-
- public void run() {
- Looper.prepare();
- Assert.assertNull(sWebCoreHandler);
- synchronized (WebViewCore.class) {
- sWebCoreHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case INITIALIZE:
- WebViewCore core = (WebViewCore) msg.obj;
- core.initialize();
- break;
-
- case REDUCE_PRIORITY:
- // 3 is an adjustable number.
- Process.setThreadPriority(
- Process.THREAD_PRIORITY_DEFAULT + 3 *
- Process.THREAD_PRIORITY_LESS_FAVORABLE);
- break;
-
- case RESUME_PRIORITY:
- Process.setThreadPriority(
- Process.THREAD_PRIORITY_DEFAULT);
- break;
-
- case CACHE_TICKER:
- if (!mCacheTickersBlocked) {
- CacheManager.endCacheTransaction();
- CacheManager.startCacheTransaction();
- sendMessageDelayed(
- obtainMessage(CACHE_TICKER),
- CACHE_TICKER_INTERVAL);
- }
- break;
-
- case BLOCK_CACHE_TICKER:
- if (CacheManager.endCacheTransaction()) {
- mCacheTickersBlocked = true;
- }
- break;
-
- case RESUME_CACHE_TICKER:
- if (CacheManager.startCacheTransaction()) {
- mCacheTickersBlocked = false;
- }
- break;
- }
- }
- };
- WebViewCore.class.notify();
- }
- Looper.loop();
- }
- }
-
- static class FocusData {
- FocusData() {}
- FocusData(FocusData d) {
- mMoveGeneration = d.mMoveGeneration;
- mBuildGeneration = d.mBuildGeneration;
- mFrame = d.mFrame;
- mNode = d.mNode;
- mX = d.mX;
- mY = d.mY;
- mIgnoreNullFocus = d.mIgnoreNullFocus;
- }
- int mMoveGeneration;
- int mBuildGeneration;
- int mFrame;
- int mNode;
- int mX;
- int mY;
- boolean mIgnoreNullFocus;
- }
-
- static class TouchUpData {
- int mMoveGeneration;
- int mBuildGeneration;
- int mFrame;
- int mNode;
- int mX;
- int mY;
- int mSize;
- boolean mIsClick;
- boolean mRetry;
- }
-
- static class TouchEventData {
- int mAction; // MotionEvent.getAction()
- int mX;
- int mY;
- }
-
- static final String[] HandlerDebugString = {
- "LOAD_URL", // = 100;
- "STOP_LOADING", // = 101;
- "RELOAD", // = 102;
- "KEY_DOWN", // = 103;
- "KEY_UP", // = 104;
- "VIEW_SIZE_CHANGED", // = 105;
- "GO_BACK_FORWARD", // = 106;
- "SET_SCROLL_OFFSET", // = 107;
- "RESTORE_STATE", // = 108;
- "PAUSE_TIMERS", // = 109;
- "RESUME_TIMERS", // = 110;
- "CLEAR_CACHE", // = 111;
- "CLEAR_HISTORY", // = 112;
- "SET_SELECTION", // = 113;
- "REPLACE_TEXT", // = 114;
- "PASS_TO_JS", // = 115;
- "SET_GLOBAL_BOUNDS", // = 116;
- "UPDATE_CACHE_AND_TEXT_ENTRY", // = 117;
- "CLICK", // = 118;
- "119",
- "DOC_HAS_IMAGES", // = 120;
- "SET_SNAP_ANCHOR", // = 121;
- "DELETE_SELECTION", // = 122;
- "LISTBOX_CHOICES", // = 123;
- "SINGLE_LISTBOX_CHOICE", // = 124;
- "125",
- "SET_BACKGROUND_COLOR", // = 126;
- "UNBLOCK_FOCUS", // = 127;
- "SAVE_DOCUMENT_STATE", // = 128;
- "GET_SELECTION", // = 129;
- "WEBKIT_DRAW", // = 130;
- "SYNC_SCROLL", // = 131;
- "REFRESH_PLUGINS", // = 132;
- "SPLIT_PICTURE_SET", // = 133;
- "CLEAR_CONTENT", // = 134;
- "SET_FINAL_FOCUS", // = 135;
- "SET_KIT_FOCUS", // = 136;
- "REQUEST_FOCUS_HREF", // = 137;
- "ADD_JS_INTERFACE", // = 138;
- "LOAD_DATA", // = 139;
- "TOUCH_UP", // = 140;
- "TOUCH_EVENT", // = 141;
- };
-
- class EventHub {
- // Message Ids
- static final int LOAD_URL = 100;
- static final int STOP_LOADING = 101;
- static final int RELOAD = 102;
- static final int KEY_DOWN = 103;
- static final int KEY_UP = 104;
- static final int VIEW_SIZE_CHANGED = 105;
- static final int GO_BACK_FORWARD = 106;
- static final int SET_SCROLL_OFFSET = 107;
- static final int RESTORE_STATE = 108;
- static final int PAUSE_TIMERS = 109;
- static final int RESUME_TIMERS = 110;
- static final int CLEAR_CACHE = 111;
- static final int CLEAR_HISTORY = 112;
- static final int SET_SELECTION = 113;
- static final int REPLACE_TEXT = 114;
- static final int PASS_TO_JS = 115;
- static final int SET_GLOBAL_BOUNDS = 116;
- static final int UPDATE_CACHE_AND_TEXT_ENTRY = 117;
- static final int CLICK = 118;
- static final int DOC_HAS_IMAGES = 120;
- static final int SET_SNAP_ANCHOR = 121;
- static final int DELETE_SELECTION = 122;
- static final int LISTBOX_CHOICES = 123;
- static final int SINGLE_LISTBOX_CHOICE = 124;
- static final int SET_BACKGROUND_COLOR = 126;
- static final int UNBLOCK_FOCUS = 127;
- static final int SAVE_DOCUMENT_STATE = 128;
- static final int GET_SELECTION = 129;
- static final int WEBKIT_DRAW = 130;
- static final int SYNC_SCROLL = 131;
- static final int REFRESH_PLUGINS = 132;
- static final int SPLIT_PICTURE_SET = 133;
- static final int CLEAR_CONTENT = 134;
-
- // UI nav messages
- static final int SET_FINAL_FOCUS = 135;
- static final int SET_KIT_FOCUS = 136;
- static final int REQUEST_FOCUS_HREF = 137;
- static final int ADD_JS_INTERFACE = 138;
- static final int LOAD_DATA = 139;
-
- // motion
- static final int TOUCH_UP = 140;
- // message used to pass UI touch events to WebCore
- static final int TOUCH_EVENT = 141;
-
- // Network-based messaging
- static final int CLEAR_SSL_PREF_TABLE = 150;
-
- // Test harness messages
- static final int REQUEST_EXT_REPRESENTATION = 160;
- static final int REQUEST_DOC_AS_TEXT = 161;
-
- // debugging
- static final int DUMP_DOMTREE = 170;
- static final int DUMP_RENDERTREE = 171;
- static final int DUMP_NAVTREE = 172;
-
- // private message ids
- private static final int DESTROY = 200;
-
- // flag values passed to message SET_FINAL_FOCUS
- static final int NO_FOCUS_CHANGE_BLOCK = 0;
- static final int BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP = 1;
-
- // Private handler for WebCore messages.
- private Handler mHandler;
- // Message queue for containing messages before the WebCore thread is
- // ready.
- private ArrayList<Message> mMessages = new ArrayList<Message>();
- // Flag for blocking messages. This is used during DESTROY to avoid
- // posting more messages to the EventHub or to WebView's event handler.
- private boolean mBlockMessages;
-
- private int mTid;
- private int mSavedPriority;
-
- /**
- * Prevent other classes from creating an EventHub.
- */
- private EventHub() {}
-
- /**
- * Transfer all messages to the newly created webcore thread handler.
- */
- private void transferMessages() {
- mTid = Process.myTid();
- mSavedPriority = Process.getThreadPriority(mTid);
-
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, msg.what < LOAD_URL || msg.what
- > TOUCH_EVENT ? Integer.toString(msg.what)
- : HandlerDebugString[msg.what - LOAD_URL]);
- }
- switch (msg.what) {
- case WEBKIT_DRAW:
- webkitDraw();
- break;
-
- case DESTROY:
- // Time to take down the world. Cancel all pending
- // loads and destroy the native view and frame.
- mBrowserFrame.destroy();
- mBrowserFrame = null;
- mNativeClass = 0;
- break;
-
- case LOAD_URL:
- loadUrl((String) msg.obj);
- break;
-
- case LOAD_DATA:
- HashMap loadParams = (HashMap) msg.obj;
- String baseUrl = (String) loadParams.get("baseUrl");
- if (baseUrl != null) {
- int i = baseUrl.indexOf(':');
- if (i > 0) {
- /*
- * In 1.0, {@link
- * WebView#loadDataWithBaseURL} can access
- * local asset files as long as the data is
- * valid. In the new WebKit, the restriction
- * is tightened. To be compatible with 1.0,
- * we automatically add the scheme of the
- * baseUrl for local access as long as it is
- * not http(s)/ftp(s)/about/javascript
- */
- String scheme = baseUrl.substring(0, i);
- if (!scheme.startsWith("http") &&
- !scheme.startsWith("ftp") &&
- !scheme.startsWith("about") &&
- !scheme.startsWith("javascript")) {
- nativeRegisterURLSchemeAsLocal(scheme);
- }
- }
- }
- mBrowserFrame.loadData(baseUrl,
- (String) loadParams.get("data"),
- (String) loadParams.get("mimeType"),
- (String) loadParams.get("encoding"),
- (String) loadParams.get("failUrl"));
- break;
-
- case STOP_LOADING:
- // If the WebCore has committed the load, but not
- // finished the first layout yet, we need to set
- // first layout done to trigger the interpreted side sync
- // up with native side
- if (mBrowserFrame.committed()
- && !mBrowserFrame.firstLayoutDone()) {
- mBrowserFrame.didFirstLayout();
- }
- // Do this after syncing up the layout state.
- stopLoading();
- break;
-
- case RELOAD:
- mBrowserFrame.reload(false);
- break;
-
- case KEY_DOWN:
- key((KeyEvent) msg.obj, true);
- break;
-
- case KEY_UP:
- key((KeyEvent) msg.obj, false);
- break;
-
- case CLICK:
- nativeClick();
- break;
-
- case VIEW_SIZE_CHANGED:
- viewSizeChanged(msg.arg1, msg.arg2,
- ((Integer) msg.obj).intValue());
- break;
-
- case SET_SCROLL_OFFSET:
- // note: these are in document coordinates
- // (inv-zoom)
- nativeSetScrollOffset(msg.arg1, msg.arg2);
- break;
-
- case SET_GLOBAL_BOUNDS:
- Rect r = (Rect) msg.obj;
- nativeSetGlobalBounds(r.left, r.top, r.width(),
- r.height());
- break;
-
- case GO_BACK_FORWARD:
- // If it is a standard load and the load is not
- // committed yet, we interpret BACK as RELOAD
- if (!mBrowserFrame.committed() && msg.arg1 == -1 &&
- (mBrowserFrame.loadType() ==
- BrowserFrame.FRAME_LOADTYPE_STANDARD)) {
- mBrowserFrame.reload(true);
- } else {
- mBrowserFrame.goBackOrForward(msg.arg1);
- }
- break;
-
- case RESTORE_STATE:
- stopLoading();
- restoreState(msg.arg1);
- break;
-
- case PAUSE_TIMERS:
- mSavedPriority = Process.getThreadPriority(mTid);
- Process.setThreadPriority(mTid,
- Process.THREAD_PRIORITY_BACKGROUND);
- pauseTimers();
- if (CacheManager.disableTransaction()) {
- WebCoreThread.mCacheTickersBlocked = true;
- sWebCoreHandler.removeMessages(
- WebCoreThread.CACHE_TICKER);
- }
- break;
-
- case RESUME_TIMERS:
- Process.setThreadPriority(mTid, mSavedPriority);
- resumeTimers();
- if (CacheManager.enableTransaction()) {
- WebCoreThread.mCacheTickersBlocked = false;
- sWebCoreHandler.sendMessageDelayed(
- sWebCoreHandler.obtainMessage(
- WebCoreThread.CACHE_TICKER),
- WebCoreThread.CACHE_TICKER_INTERVAL);
- }
- break;
-
- case CLEAR_CACHE:
- mBrowserFrame.clearCache();
- if (msg.arg1 == 1) {
- CacheManager.removeAllCacheFiles();
- }
- break;
-
- case CLEAR_HISTORY:
- mCallbackProxy.getBackForwardList().
- close(mBrowserFrame.mNativeFrame);
- break;
-
- case REPLACE_TEXT:
- HashMap jMap = (HashMap) msg.obj;
- FocusData fData = (FocusData) jMap.get("focusData");
- String replace = (String) jMap.get("replace");
- int newStart =
- ((Integer) jMap.get("start")).intValue();
- int newEnd =
- ((Integer) jMap.get("end")).intValue();
- nativeReplaceTextfieldText(fData.mFrame,
- fData.mNode, fData.mX, fData.mY, msg.arg1,
- msg.arg2, replace, newStart, newEnd);
- break;
-
- case PASS_TO_JS: {
- HashMap jsMap = (HashMap) msg.obj;
- FocusData fDat = (FocusData) jsMap.get("focusData");
- KeyEvent evt = (KeyEvent) jsMap.get("event");
- int keyCode = evt.getKeyCode();
- int keyValue = evt.getUnicodeChar();
- int generation = msg.arg1;
- passToJs(fDat.mFrame, fDat.mNode, fDat.mX, fDat.mY,
- generation,
- (String) jsMap.get("currentText"),
- keyCode,
- keyValue,
- evt.isDown(),
- evt.isShiftPressed(), evt.isAltPressed(),
- evt.isSymPressed());
- break;
- }
-
- case SAVE_DOCUMENT_STATE: {
- FocusData fDat = (FocusData) msg.obj;
- nativeSaveDocumentState(fDat.mFrame);
- break;
- }
-
- case CLEAR_SSL_PREF_TABLE:
- Network.getInstance(mContext)
- .clearUserSslPrefTable();
- break;
-
- case TOUCH_UP:
- TouchUpData touchUpData = (TouchUpData) msg.obj;
- nativeTouchUp(touchUpData.mMoveGeneration,
- touchUpData.mBuildGeneration,
- touchUpData.mFrame, touchUpData.mNode,
- touchUpData.mX, touchUpData.mY,
- touchUpData.mSize, touchUpData.mIsClick,
- touchUpData.mRetry);
- break;
-
- case TOUCH_EVENT: {
- TouchEventData ted = (TouchEventData) msg.obj;
- Message.obtain(
- mWebView.mPrivateHandler,
- WebView.PREVENT_TOUCH_ID, ted.mAction,
- nativeHandleTouchEvent(ted.mAction, ted.mX,
- ted.mY) ? 1 : 0).sendToTarget();
- break;
- }
-
- case ADD_JS_INTERFACE:
- HashMap map = (HashMap) msg.obj;
- Object obj = map.get("object");
- String interfaceName = (String)
- map.get("interfaceName");
- mBrowserFrame.addJavascriptInterface(obj,
- interfaceName);
- break;
-
- case REQUEST_EXT_REPRESENTATION:
- mBrowserFrame.externalRepresentation(
- (Message) msg.obj);
- break;
-
- case REQUEST_DOC_AS_TEXT:
- mBrowserFrame.documentAsText((Message) msg.obj);
- break;
-
- case SET_FINAL_FOCUS:
- FocusData finalData = (FocusData) msg.obj;
- nativeSetFinalFocus(finalData.mFrame,
- finalData.mNode, finalData.mX,
- finalData.mY, msg.arg1
- != EventHub.NO_FOCUS_CHANGE_BLOCK);
- break;
-
- case UNBLOCK_FOCUS:
- nativeUnblockFocus();
- break;
-
- case SET_KIT_FOCUS:
- FocusData focusData = (FocusData) msg.obj;
- nativeSetKitFocus(focusData.mMoveGeneration,
- focusData.mBuildGeneration,
- focusData.mFrame, focusData.mNode,
- focusData.mX, focusData.mY,
- focusData.mIgnoreNullFocus);
- break;
-
- case REQUEST_FOCUS_HREF: {
- Message hrefMsg = (Message) msg.obj;
- String res = nativeRetrieveHref(msg.arg1, msg.arg2);
- hrefMsg.getData().putString("url", res);
- hrefMsg.sendToTarget();
- break;
- }
-
- case UPDATE_CACHE_AND_TEXT_ENTRY:
- nativeUpdateFrameCache();
- // FIXME: this should provide a minimal rectangle
- if (mWebView != null) {
- mWebView.postInvalidate();
- }
- sendUpdateTextEntry();
- break;
-
- case DOC_HAS_IMAGES:
- Message imageResult = (Message) msg.obj;
- imageResult.arg1 =
- mBrowserFrame.documentHasImages() ? 1 : 0;
- imageResult.sendToTarget();
- break;
-
- case SET_SNAP_ANCHOR:
- nativeSetSnapAnchor(msg.arg1, msg.arg2);
- break;
-
- case DELETE_SELECTION:
- FocusData delData = (FocusData) msg.obj;
- nativeDeleteSelection(delData.mFrame,
- delData.mNode, delData.mX,
- delData.mY, msg.arg1, msg.arg2);
- break;
-
- case SET_SELECTION:
- FocusData selData = (FocusData) msg.obj;
- nativeSetSelection(selData.mFrame,
- selData.mNode, selData.mX,
- selData.mY, msg.arg1, msg.arg2);
- break;
-
- case LISTBOX_CHOICES:
- SparseBooleanArray choices = (SparseBooleanArray)
- msg.obj;
- int choicesSize = msg.arg1;
- boolean[] choicesArray = new boolean[choicesSize];
- for (int c = 0; c < choicesSize; c++) {
- choicesArray[c] = choices.get(c);
- }
- nativeSendListBoxChoices(choicesArray,
- choicesSize);
- break;
-
- case SINGLE_LISTBOX_CHOICE:
- nativeSendListBoxChoice(msg.arg1);
- break;
-
- case SET_BACKGROUND_COLOR:
- nativeSetBackgroundColor(msg.arg1);
- break;
-
- case GET_SELECTION:
- String str = nativeGetSelection((Region) msg.obj);
- Message.obtain(mWebView.mPrivateHandler
- , WebView.UPDATE_CLIPBOARD, str)
- .sendToTarget();
- break;
-
- case DUMP_DOMTREE:
- nativeDumpDomTree(msg.arg1 == 1);
- break;
-
- case DUMP_RENDERTREE:
- nativeDumpRenderTree(msg.arg1 == 1);
- break;
-
- case DUMP_NAVTREE:
- nativeDumpNavTree();
- break;
-
- case SYNC_SCROLL:
- mWebkitScrollX = msg.arg1;
- mWebkitScrollY = msg.arg2;
- break;
-
- case REFRESH_PLUGINS:
- nativeRefreshPlugins(msg.arg1 != 0);
- break;
-
- case SPLIT_PICTURE_SET:
- nativeSplitContent();
- mSplitPictureIsScheduled = false;
- break;
-
- case CLEAR_CONTENT:
- // Clear the view so that onDraw() will draw nothing
- // but white background
- // (See public method WebView.clearView)
- nativeClearContent();
- break;
- }
- }
- };
- // Take all queued messages and resend them to the new handler.
- synchronized (this) {
- int size = mMessages.size();
- for (int i = 0; i < size; i++) {
- mHandler.sendMessage(mMessages.get(i));
- }
- mMessages = null;
- }
- }
-
- /**
- * Send a message internally to the queue or to the handler
- */
- private synchronized void sendMessage(Message msg) {
- if (mBlockMessages) {
- return;
- }
- if (mMessages != null) {
- mMessages.add(msg);
- } else {
- mHandler.sendMessage(msg);
- }
- }
-
- private synchronized void removeMessages(int what) {
- if (mBlockMessages) {
- return;
- }
- if (what == EventHub.WEBKIT_DRAW) {
- mDrawIsScheduled = false;
- }
- if (mMessages != null) {
- Log.w(LOGTAG, "Not supported in this case.");
- } else {
- mHandler.removeMessages(what);
- }
- }
-
- private synchronized void sendMessageDelayed(Message msg, long delay) {
- if (mBlockMessages) {
- return;
- }
- mHandler.sendMessageDelayed(msg, delay);
- }
-
- /**
- * Send a message internally to the front of the queue.
- */
- private synchronized void sendMessageAtFrontOfQueue(Message msg) {
- if (mBlockMessages) {
- return;
- }
- if (mMessages != null) {
- mMessages.add(0, msg);
- } else {
- mHandler.sendMessageAtFrontOfQueue(msg);
- }
- }
-
- /**
- * Remove all the messages.
- */
- private synchronized void removeMessages() {
- // reset mDrawIsScheduled flag as WEBKIT_DRAW may be removed
- mDrawIsScheduled = false;
- mSplitPictureIsScheduled = false;
- if (mMessages != null) {
- mMessages.clear();
- } else {
- mHandler.removeCallbacksAndMessages(null);
- }
- }
-
- /**
- * Block sending messages to the EventHub.
- */
- private synchronized void blockMessages() {
- mBlockMessages = true;
- }
- }
-
- //-------------------------------------------------------------------------
- // Methods called by host activity (in the same thread)
- //-------------------------------------------------------------------------
-
- void stopLoading() {
- if (LOGV_ENABLED) Log.v(LOGTAG, "CORE stopLoading");
- if (mBrowserFrame != null) {
- mBrowserFrame.stopLoading();
- }
- }
-
- //-------------------------------------------------------------------------
- // Methods called by WebView
- // If it refers to local variable, it needs synchronized().
- // If it needs WebCore, it has to send message.
- //-------------------------------------------------------------------------
-
- void sendMessage(Message msg) {
- mEventHub.sendMessage(msg);
- }
-
- void sendMessage(int what) {
- mEventHub.sendMessage(Message.obtain(null, what));
- }
-
- void sendMessage(int what, Object obj) {
- mEventHub.sendMessage(Message.obtain(null, what, obj));
- }
-
- void sendMessage(int what, int arg1) {
- // just ignore the second argument (make it 0)
- mEventHub.sendMessage(Message.obtain(null, what, arg1, 0));
- }
-
- void sendMessage(int what, int arg1, int arg2) {
- mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2));
- }
-
- void sendMessage(int what, int arg1, Object obj) {
- // just ignore the second argument (make it 0)
- mEventHub.sendMessage(Message.obtain(null, what, arg1, 0, obj));
- }
-
- void sendMessage(int what, int arg1, int arg2, Object obj) {
- mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2, obj));
- }
-
- void sendMessageDelayed(int what, Object obj, long delay) {
- mEventHub.sendMessageDelayed(Message.obtain(null, what, obj), delay);
- }
-
- void removeMessages(int what) {
- mEventHub.removeMessages(what);
- }
-
- void removeMessages() {
- mEventHub.removeMessages();
- }
-
- /**
- * Removes pending messages and trigger a DESTROY message to send to
- * WebCore.
- * Called from UI thread.
- */
- void destroy() {
- // We don't want anyone to post a message between removing pending
- // messages and sending the destroy message.
- synchronized (mEventHub) {
- mEventHub.removeMessages();
- mEventHub.sendMessageAtFrontOfQueue(
- Message.obtain(null, EventHub.DESTROY));
- mEventHub.blockMessages();
- mWebView = null;
- }
- }
-
- //-------------------------------------------------------------------------
- // WebViewCore private methods
- //-------------------------------------------------------------------------
-
- private void loadUrl(String url) {
- if (LOGV_ENABLED) Log.v(LOGTAG, " CORE loadUrl " + url);
- mBrowserFrame.loadUrl(url);
- }
-
- private void key(KeyEvent evt, boolean isDown) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "CORE key at " + System.currentTimeMillis() + ", "
- + evt);
- }
- if (!nativeKey(evt.getKeyCode(), evt.getUnicodeChar(),
- evt.getRepeatCount(), evt.isShiftPressed(), evt.isAltPressed(),
- isDown)) {
- // bubble up the event handling
- mCallbackProxy.onUnhandledKeyEvent(evt);
- }
- }
-
- // These values are used to avoid requesting a layout based on old values
- private int mCurrentViewWidth = 0;
- private int mCurrentViewHeight = 0;
-
- // Define a minimum screen width so that we won't wrap the paragraph to one
- // word per line during zoom-in.
- private static final int MIN_SCREEN_WIDTH = 160;
-
- // notify webkit that our virtual view size changed size (after inv-zoom)
- private void viewSizeChanged(int w, int h, int viewWidth) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "CORE onSizeChanged");
- if (w == 0) {
- Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
- return;
- }
- // negative scale indicate that WebCore should reuse the current scale
- float scale = (float) viewWidth / w;
- if (mSettings.getUseWideViewPort()
- && (w < mViewportWidth || mViewportWidth == -1)) {
- int width = mViewportWidth;
- int screenWidth = Math.max(w, MIN_SCREEN_WIDTH);
- if (mViewportWidth == -1) {
- if (mSettings.getLayoutAlgorithm() ==
- WebSettings.LayoutAlgorithm.NORMAL) {
- width = WebView.ZOOM_OUT_WIDTH;
- } else {
- /*
- * if a page's minimum preferred width is wider than the
- * given "w", use it instead to get better layout result. If
- * we start a page with MAX_ZOOM_WIDTH, "w" will be always
- * wider. If we start a page with screen width, due to the
- * delay between {@link #didFirstLayout} and
- * {@link #viewSizeChanged},
- * {@link #nativeGetContentMinPrefWidth} will return a more
- * accurate value than initial 0 to result a better layout.
- * In the worse case, the native width will be adjusted when
- * next zoom or screen orientation change happens.
- */
- int minContentWidth = nativeGetContentMinPrefWidth();
- if (minContentWidth > WebView.MAX_FLOAT_CONTENT_WIDTH) {
- // keep the same width and screen width so that there is
- // no reflow when zoom-out
- width = minContentWidth;
- screenWidth = Math.min(screenWidth, Math.abs(viewWidth));
- } else {
- width = Math.max(w, minContentWidth);
- }
- }
- }
- nativeSetSize(width, Math.round((float) width * h / w),
- screenWidth, scale, w, h);
- } else {
- nativeSetSize(w, h, w, scale, w, h);
- }
- // Remember the current width and height
- boolean needInvalidate = (mCurrentViewWidth == 0);
- mCurrentViewWidth = w;
- mCurrentViewHeight = h;
- if (needInvalidate) {
- // ensure {@link #webkitDraw} is called as we were blocking in
- // {@link #contentDraw} when mCurrentViewWidth is 0
- if (LOGV_ENABLED) Log.v(LOGTAG, "viewSizeChanged");
- contentDraw();
- }
- mEventHub.sendMessage(Message.obtain(null,
- EventHub.UPDATE_CACHE_AND_TEXT_ENTRY));
- }
-
- private void sendUpdateTextEntry() {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.UPDATE_TEXT_ENTRY_MSG_ID).sendToTarget();
- }
- }
-
- // Used to avoid posting more than one draw message.
- private boolean mDrawIsScheduled;
-
- // Used to avoid posting more than one split picture message.
- private boolean mSplitPictureIsScheduled;
-
- // Used to suspend drawing.
- private boolean mDrawIsPaused;
-
- // Used to end scale+scroll mode, accessed by both threads
- boolean mEndScaleZoom = false;
-
- public class DrawData {
- public DrawData() {
- mInvalRegion = new Region();
- mWidthHeight = new Point();
- }
- public Region mInvalRegion;
- public Point mViewPoint;
- public Point mWidthHeight;
- }
-
- private void webkitDraw() {
- mDrawIsScheduled = false;
- DrawData draw = new DrawData();
- if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw start");
- if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight)
- == false) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw abort");
- return;
- }
- if (mWebView != null) {
- // Send the native view size that was used during the most recent
- // layout.
- draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
- if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
- Message.obtain(mWebView.mPrivateHandler,
- WebView.NEW_PICTURE_MSG_ID, nativeGetContentMinPrefWidth(),
- 0, draw).sendToTarget();
- nativeCheckNavCache();
- if (mWebkitScrollX != 0 || mWebkitScrollY != 0) {
- // as we have the new picture, try to sync the scroll position
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SYNC_SCROLL_TO_MSG_ID, mWebkitScrollX,
- mWebkitScrollY).sendToTarget();
- mWebkitScrollX = mWebkitScrollY = 0;
- }
- // nativeSnapToAnchor() needs to be called after NEW_PICTURE_MSG_ID
- // is sent, so that scroll will be based on the new content size.
- nativeSnapToAnchor();
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // These are called from the UI thread, not our thread
-
- static final int ZOOM_BITS = Paint.FILTER_BITMAP_FLAG |
- Paint.DITHER_FLAG |
- Paint.SUBPIXEL_TEXT_FLAG;
- static final int SCROLL_BITS = Paint.FILTER_BITMAP_FLAG |
- Paint.DITHER_FLAG;
-
- final DrawFilter mZoomFilter =
- new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG);
- final DrawFilter mScrollFilter =
- new PaintFlagsDrawFilter(SCROLL_BITS, 0);
-
- /* package */ void drawContentPicture(Canvas canvas, int color,
- boolean animatingZoom,
- boolean animatingScroll) {
- DrawFilter df = null;
- if (animatingZoom) {
- df = mZoomFilter;
- } else if (animatingScroll) {
- df = mScrollFilter;
- }
- canvas.setDrawFilter(df);
- boolean tookTooLong = nativeDrawContent(canvas, color);
- canvas.setDrawFilter(null);
- if (tookTooLong && mSplitPictureIsScheduled == false) {
- mSplitPictureIsScheduled = true;
- sendMessage(EventHub.SPLIT_PICTURE_SET);
- }
- }
-
- /*package*/ Picture copyContentPicture() {
- Picture result = new Picture();
- nativeCopyContentToPicture(result);
- return result;
- }
-
- static void pauseUpdate(WebViewCore core) {
- // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages
- sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY);
- sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY);
- sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler
- .obtainMessage(WebCoreThread.REDUCE_PRIORITY));
- // Note: there is one possible failure mode. If pauseUpdate() is called
- // from UI thread while in webcore thread WEBKIT_DRAW is just pulled out
- // of the queue and about to be executed. mDrawIsScheduled may be set to
- // false in webkitDraw(). So update won't be blocked. But at least the
- // webcore thread priority is still lowered.
- if (core != null) {
- synchronized (core) {
- core.mDrawIsPaused = true;
- core.mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
- }
- }
- }
-
- static void resumeUpdate(WebViewCore core) {
- // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages
- sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY);
- sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY);
- sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler
- .obtainMessage(WebCoreThread.RESUME_PRIORITY));
- if (core != null) {
- synchronized (core) {
- core.mDrawIsScheduled = false;
- core.mDrawIsPaused = false;
- if (LOGV_ENABLED) Log.v(LOGTAG, "resumeUpdate");
- core.contentDraw();
- }
- }
- }
-
- static void startCacheTransaction() {
- sWebCoreHandler.sendMessage(sWebCoreHandler
- .obtainMessage(WebCoreThread.RESUME_CACHE_TICKER));
- }
-
- static void endCacheTransaction() {
- sWebCoreHandler.sendMessage(sWebCoreHandler
- .obtainMessage(WebCoreThread.BLOCK_CACHE_TICKER));
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- private void restoreState(int index) {
- WebBackForwardList list = mCallbackProxy.getBackForwardList();
- int size = list.getSize();
- for (int i = 0; i < size; i++) {
- list.getItemAtIndex(i).inflate(mBrowserFrame.mNativeFrame);
- }
- mBrowserFrame.mLoadInitFromJava = true;
- list.restoreIndex(mBrowserFrame.mNativeFrame, index);
- mBrowserFrame.mLoadInitFromJava = false;
- }
-
- //-------------------------------------------------------------------------
- // Implement abstract methods in WebViewCore, native WebKit callback part
- //-------------------------------------------------------------------------
-
- // called from JNI or WebView thread
- /* package */ void contentDraw() {
- // don't update the Picture until we have an initial width and finish
- // the first layout
- if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) {
- return;
- }
- // only fire an event if this is our first request
- synchronized (this) {
- if (mDrawIsPaused || mDrawIsScheduled) {
- return;
- }
- mDrawIsScheduled = true;
- mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
- }
- }
-
- // called by JNI
- private void contentScrollBy(int dx, int dy, boolean animate) {
- if (!mBrowserFrame.firstLayoutDone()) {
- // Will this happen? If yes, we need to do something here.
- return;
- }
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SCROLL_BY_MSG_ID, dx, dy,
- new Boolean(animate)).sendToTarget();
- }
- }
-
- // called by JNI
- private void contentScrollTo(int x, int y) {
- if (!mBrowserFrame.firstLayoutDone()) {
- /*
- * WebKit restore state will be called before didFirstLayout(),
- * remember the position as it has to be applied after restoring
- * zoom factor which is controlled by screenWidth.
- */
- mRestoredX = x;
- mRestoredY = y;
- return;
- }
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SCROLL_TO_MSG_ID, x, y).sendToTarget();
- }
- }
-
- // called by JNI
- private void contentSpawnScrollTo(int x, int y) {
- if (!mBrowserFrame.firstLayoutDone()) {
- /*
- * WebKit restore state will be called before didFirstLayout(),
- * remember the position as it has to be applied after restoring
- * zoom factor which is controlled by screenWidth.
- */
- mRestoredX = x;
- mRestoredY = y;
- return;
- }
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SPAWN_SCROLL_TO_MSG_ID, x, y).sendToTarget();
- }
- }
-
- // called by JNI
- private void sendMarkNodeInvalid(int node) {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.MARK_NODE_INVALID_ID, node, 0).sendToTarget();
- }
- }
-
- // called by JNI
- private void sendNotifyFocusSet() {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.NOTIFY_FOCUS_SET_MSG_ID).sendToTarget();
- }
- }
-
- // called by JNI
- private void sendNotifyProgressFinished() {
- sendUpdateTextEntry();
- // as CacheManager can behave based on database transaction, we need to
- // call tick() to trigger endTransaction
- sWebCoreHandler.removeMessages(WebCoreThread.CACHE_TICKER);
- sWebCoreHandler.sendMessage(sWebCoreHandler
- .obtainMessage(WebCoreThread.CACHE_TICKER));
- contentDraw();
- }
-
- // called by JNI
- private void sendRecomputeFocus() {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.RECOMPUTE_FOCUS_MSG_ID).sendToTarget();
- }
- }
-
- /* Called by JNI. The coordinates are in doc coordinates, so they need to
- be scaled before they can be used by the view system, which happens
- in WebView since it (and its thread) know the current scale factor.
- */
- private void sendViewInvalidate(int left, int top, int right, int bottom) {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.INVAL_RECT_MSG_ID,
- new Rect(left, top, right, bottom)).sendToTarget();
- }
- }
-
- /* package */ WebView getWebView() {
- return mWebView;
- }
-
- private native void setViewportSettingsFromNative();
-
- // called by JNI
- private void didFirstLayout() {
- // Trick to ensure that the Picture has the exact height for the content
- // by forcing to layout with 0 height after the page is ready, which is
- // indicated by didFirstLayout. This is essential to get rid of the
- // white space in the GMail which uses WebView for message view.
- if (mWebView != null && mWebView.mHeightCanMeasure) {
- mWebView.mLastHeightSent = 0;
- // Send a negative screen width to indicate that WebCore should
- // reuse the current scale
- mEventHub.sendMessage(Message.obtain(null,
- EventHub.VIEW_SIZE_CHANGED, mWebView.mLastWidthSent,
- mWebView.mLastHeightSent, -mWebView.mLastWidthSent));
- }
-
- mBrowserFrame.didFirstLayout();
-
- // reset the scroll position as it is a new page now
- mWebkitScrollX = mWebkitScrollY = 0;
-
- // set the viewport settings from WebKit
- setViewportSettingsFromNative();
-
- // infer the values if they are not defined.
- if (mViewportWidth == 0) {
- if (mViewportInitialScale == 0) {
- mViewportInitialScale = 100;
- }
- if (mViewportMinimumScale == 0) {
- mViewportMinimumScale = 100;
- }
- }
- if (mViewportUserScalable == false) {
- mViewportInitialScale = 100;
- mViewportMinimumScale = 100;
- mViewportMaximumScale = 100;
- }
- if (mViewportMinimumScale > mViewportInitialScale) {
- if (mViewportInitialScale == 0) {
- mViewportInitialScale = mViewportMinimumScale;
- } else {
- mViewportMinimumScale = mViewportInitialScale;
- }
- }
- if (mViewportMaximumScale > 0) {
- if (mViewportMaximumScale < mViewportInitialScale) {
- mViewportMaximumScale = mViewportInitialScale;
- } else if (mViewportInitialScale == 0) {
- mViewportInitialScale = mViewportMaximumScale;
- }
- }
- if (mViewportWidth < 0 && mViewportInitialScale == 100) {
- mViewportWidth = 0;
- }
-
- // now notify webview
- if (mWebView != null) {
- HashMap scaleLimit = new HashMap();
- scaleLimit.put("minScale", mViewportMinimumScale);
- scaleLimit.put("maxScale", mViewportMaximumScale);
-
- if (mRestoredScale > 0) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.DID_FIRST_LAYOUT_MSG_ID, mRestoredScale, 0,
- scaleLimit).sendToTarget();
- mRestoredScale = 0;
- } else {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.DID_FIRST_LAYOUT_MSG_ID, mViewportInitialScale,
- mViewportWidth, scaleLimit).sendToTarget();
- }
-
- // if no restored offset, move the new page to (0, 0)
- Message.obtain(mWebView.mPrivateHandler, WebView.SCROLL_TO_MSG_ID,
- mRestoredX, mRestoredY).sendToTarget();
- mRestoredX = mRestoredY = 0;
-
- // force an early draw for quick feedback after the first layout
- if (mCurrentViewWidth != 0) {
- synchronized (this) {
- if (mDrawIsScheduled) {
- mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
- }
- mDrawIsScheduled = true;
- mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
- EventHub.WEBKIT_DRAW));
- }
- }
- }
- }
-
- // called by JNI
- private void restoreScale(int scale) {
- if (mBrowserFrame.firstLayoutDone() == false) {
- mRestoredScale = scale;
- }
- }
-
- // called by JNI
- private void needTouchEvents(boolean need) {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.WEBCORE_NEED_TOUCH_EVENTS, need ? 1 : 0, 0)
- .sendToTarget();
- }
- }
-
- // called by JNI
- private void updateTextfield(int ptr, boolean changeToPassword,
- String text, int textGeneration) {
- if (mWebView != null) {
- Message msg = Message.obtain(mWebView.mPrivateHandler,
- WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr,
- textGeneration, text);
- msg.getData().putBoolean("password", changeToPassword);
- msg.sendToTarget();
- }
- }
-
- // these must be in document space (i.e. not scaled/zoomed).
- private native void nativeSetScrollOffset(int dx, int dy);
-
- private native void nativeSetGlobalBounds(int x, int y, int w, int h);
-
- // called by JNI
- private void requestListBox(String[] array, boolean[] enabledArray,
- int[] selectedArray) {
- if (mWebView != null) {
- mWebView.requestListBox(array, enabledArray, selectedArray);
- }
- }
-
- // called by JNI
- private void requestListBox(String[] array, boolean[] enabledArray,
- int selection) {
- if (mWebView != null) {
- mWebView.requestListBox(array, enabledArray, selection);
- }
-
- }
-}
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
deleted file mode 100644
index 1004e30..0000000
--- a/core/java/android/webkit/WebViewDatabase.java
+++ /dev/null
@@ -1,967 +0,0 @@
-/*
- * Copyright (C) 2007 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 java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.Map.Entry;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteStatement;
-import android.util.Log;
-import android.webkit.CookieManager.Cookie;
-import android.webkit.CacheManager.CacheResult;
-
-public class WebViewDatabase {
- private static final String DATABASE_FILE = "webview.db";
- private static final String CACHE_DATABASE_FILE = "webviewCache.db";
-
- // log tag
- protected static final String LOGTAG = "webviewdatabase";
-
- private static final int DATABASE_VERSION = 9;
- // 2 -> 3 Modified Cache table to allow cache of redirects
- // 3 -> 4 Added Oma-Downloads table
- // 4 -> 5 Modified Cache table to support persistent contentLength
- // 5 -> 4 Removed Oma-Downoads table
- // 5 -> 6 Add INDEX for cache table
- // 6 -> 7 Change cache localPath from int to String
- // 7 -> 8 Move cache to its own db
- // 8 -> 9 Store both scheme and host when storing passwords
- private static final int CACHE_DATABASE_VERSION = 1;
-
- private static WebViewDatabase mInstance = null;
-
- private static SQLiteDatabase mDatabase = null;
- private static SQLiteDatabase mCacheDatabase = null;
-
- // synchronize locks
- private final Object mCookieLock = new Object();
- private final Object mPasswordLock = new Object();
- private final Object mFormLock = new Object();
- private final Object mHttpAuthLock = new Object();
-
- private static final String mTableNames[] = {
- "cookies", "password", "formurl", "formdata", "httpauth"
- };
-
- // Table ids (they are index to mTableNames)
- private static final int TABLE_COOKIES_ID = 0;
-
- private static final int TABLE_PASSWORD_ID = 1;
-
- private static final int TABLE_FORMURL_ID = 2;
-
- private static final int TABLE_FORMDATA_ID = 3;
-
- private static final int TABLE_HTTPAUTH_ID = 4;
-
- // column id strings for "_id" which can be used by any table
- private static final String ID_COL = "_id";
-
- private static final String[] ID_PROJECTION = new String[] {
- "_id"
- };
-
- // column id strings for "cookies" table
- private static final String COOKIES_NAME_COL = "name";
-
- private static final String COOKIES_VALUE_COL = "value";
-
- private static final String COOKIES_DOMAIN_COL = "domain";
-
- private static final String COOKIES_PATH_COL = "path";
-
- private static final String COOKIES_EXPIRES_COL = "expires";
-
- private static final String COOKIES_SECURE_COL = "secure";
-
- // column id strings for "cache" table
- private static final String CACHE_URL_COL = "url";
-
- private static final String CACHE_FILE_PATH_COL = "filepath";
-
- private static final String CACHE_LAST_MODIFY_COL = "lastmodify";
-
- private static final String CACHE_ETAG_COL = "etag";
-
- private static final String CACHE_EXPIRES_COL = "expires";
-
- private static final String CACHE_MIMETYPE_COL = "mimetype";
-
- private static final String CACHE_ENCODING_COL = "encoding";
-
- private static final String CACHE_HTTP_STATUS_COL = "httpstatus";
-
- private static final String CACHE_LOCATION_COL = "location";
-
- private static final String CACHE_CONTENTLENGTH_COL = "contentlength";
-
- // column id strings for "password" table
- private static final String PASSWORD_HOST_COL = "host";
-
- private static final String PASSWORD_USERNAME_COL = "username";
-
- private static final String PASSWORD_PASSWORD_COL = "password";
-
- // column id strings for "formurl" table
- private static final String FORMURL_URL_COL = "url";
-
- // column id strings for "formdata" table
- private static final String FORMDATA_URLID_COL = "urlid";
-
- private static final String FORMDATA_NAME_COL = "name";
-
- private static final String FORMDATA_VALUE_COL = "value";
-
- // column id strings for "httpauth" table
- private static final String HTTPAUTH_HOST_COL = "host";
-
- private static final String HTTPAUTH_REALM_COL = "realm";
-
- private static final String HTTPAUTH_USERNAME_COL = "username";
-
- private static final String HTTPAUTH_PASSWORD_COL = "password";
-
- // use InsertHelper to improve insert performance by 40%
- private static DatabaseUtils.InsertHelper mCacheInserter;
- private static int mCacheUrlColIndex;
- private static int mCacheFilePathColIndex;
- private static int mCacheLastModifyColIndex;
- private static int mCacheETagColIndex;
- private static int mCacheExpiresColIndex;
- private static int mCacheMimeTypeColIndex;
- private static int mCacheEncodingColIndex;
- private static int mCacheHttpStatusColIndex;
- private static int mCacheLocationColIndex;
- private static int mCacheContentLengthColIndex;
-
- private static int mCacheTransactionRefcount;
-
- private WebViewDatabase() {
- // Singleton only, use getInstance()
- }
-
- public static synchronized WebViewDatabase getInstance(Context context) {
- if (mInstance == null) {
- mInstance = new WebViewDatabase();
- mDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0, null);
-
- // mDatabase should not be null,
- // the only case is RequestAPI test has problem to create db
- if (mDatabase != null && mDatabase.getVersion() != DATABASE_VERSION) {
- mDatabase.beginTransaction();
- try {
- upgradeDatabase();
- mDatabase.setTransactionSuccessful();
- } finally {
- mDatabase.endTransaction();
- }
- }
-
- if (mDatabase != null) {
- // use per table Mutex lock, turn off database lock, this
- // improves performance as database's ReentrantLock is expansive
- mDatabase.setLockingEnabled(false);
- }
-
- mCacheDatabase = context.openOrCreateDatabase(CACHE_DATABASE_FILE,
- 0, null);
-
- // mCacheDatabase should not be null,
- // the only case is RequestAPI test has problem to create db
- if (mCacheDatabase != null
- && mCacheDatabase.getVersion() != CACHE_DATABASE_VERSION) {
- mCacheDatabase.beginTransaction();
- try {
- upgradeCacheDatabase();
- bootstrapCacheDatabase();
- mCacheDatabase.setTransactionSuccessful();
- } finally {
- mCacheDatabase.endTransaction();
- }
- // Erase the files from the file system in the
- // case that the database was updated and the
- // there were existing cache content
- CacheManager.removeAllCacheFiles();
- }
-
- if (mCacheDatabase != null) {
- // use InsertHelper for faster insertion
- mCacheInserter = new DatabaseUtils.InsertHelper(mCacheDatabase,
- "cache");
- mCacheUrlColIndex = mCacheInserter
- .getColumnIndex(CACHE_URL_COL);
- mCacheFilePathColIndex = mCacheInserter
- .getColumnIndex(CACHE_FILE_PATH_COL);
- mCacheLastModifyColIndex = mCacheInserter
- .getColumnIndex(CACHE_LAST_MODIFY_COL);
- mCacheETagColIndex = mCacheInserter
- .getColumnIndex(CACHE_ETAG_COL);
- mCacheExpiresColIndex = mCacheInserter
- .getColumnIndex(CACHE_EXPIRES_COL);
- mCacheMimeTypeColIndex = mCacheInserter
- .getColumnIndex(CACHE_MIMETYPE_COL);
- mCacheEncodingColIndex = mCacheInserter
- .getColumnIndex(CACHE_ENCODING_COL);
- mCacheHttpStatusColIndex = mCacheInserter
- .getColumnIndex(CACHE_HTTP_STATUS_COL);
- mCacheLocationColIndex = mCacheInserter
- .getColumnIndex(CACHE_LOCATION_COL);
- mCacheContentLengthColIndex = mCacheInserter
- .getColumnIndex(CACHE_CONTENTLENGTH_COL);
- }
- }
-
- return mInstance;
- }
-
- private static void upgradeDatabase() {
- int oldVersion = mDatabase.getVersion();
- if (oldVersion != 0) {
- Log.i(LOGTAG, "Upgrading database from version "
- + oldVersion + " to "
- + DATABASE_VERSION + ", which will destroy old data");
- }
- boolean justPasswords = 8 == oldVersion && 9 == DATABASE_VERSION;
- if (!justPasswords) {
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_COOKIES_ID]);
- mDatabase.execSQL("DROP TABLE IF EXISTS cache");
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_FORMURL_ID]);
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_FORMDATA_ID]);
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_HTTPAUTH_ID]);
- }
- mDatabase.execSQL("DROP TABLE IF EXISTS "
- + mTableNames[TABLE_PASSWORD_ID]);
-
- mDatabase.setVersion(DATABASE_VERSION);
-
- if (!justPasswords) {
- // cookies
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_COOKIES_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, "
- + COOKIES_NAME_COL + " TEXT, " + COOKIES_VALUE_COL
- + " TEXT, " + COOKIES_DOMAIN_COL + " TEXT, "
- + COOKIES_PATH_COL + " TEXT, " + COOKIES_EXPIRES_COL
- + " INTEGER, " + COOKIES_SECURE_COL + " INTEGER" + ");");
- mDatabase.execSQL("CREATE INDEX cookiesIndex ON "
- + mTableNames[TABLE_COOKIES_ID] + " (path)");
-
- // formurl
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMURL_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, " + FORMURL_URL_COL
- + " TEXT" + ");");
-
- // formdata
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMDATA_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, "
- + FORMDATA_URLID_COL + " INTEGER, " + FORMDATA_NAME_COL
- + " TEXT, " + FORMDATA_VALUE_COL + " TEXT," + " UNIQUE ("
- + FORMDATA_URLID_COL + ", " + FORMDATA_NAME_COL + ", "
- + FORMDATA_VALUE_COL + ") ON CONFLICT IGNORE);");
-
- // httpauth
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_HTTPAUTH_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, "
- + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
- + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
- + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
- + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL + ", "
- + HTTPAUTH_USERNAME_COL + ") ON CONFLICT REPLACE);");
- }
- // passwords
- mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID]
- + " (" + ID_COL + " INTEGER PRIMARY KEY, "
- + PASSWORD_HOST_COL + " TEXT, " + PASSWORD_USERNAME_COL
- + " TEXT, " + PASSWORD_PASSWORD_COL + " TEXT," + " UNIQUE ("
- + PASSWORD_HOST_COL + ", " + PASSWORD_USERNAME_COL
- + ") ON CONFLICT REPLACE);");
- }
-
- private static void upgradeCacheDatabase() {
- int oldVersion = mCacheDatabase.getVersion();
- if (oldVersion != 0) {
- Log.i(LOGTAG, "Upgrading cache database from version "
- + oldVersion + " to "
- + DATABASE_VERSION + ", which will destroy all old data");
- }
- mCacheDatabase.execSQL("DROP TABLE IF EXISTS cache");
- mCacheDatabase.setVersion(CACHE_DATABASE_VERSION);
- }
-
- private static void bootstrapCacheDatabase() {
- if (mCacheDatabase != null) {
- mCacheDatabase.execSQL("CREATE TABLE cache"
- + " (" + ID_COL + " INTEGER PRIMARY KEY, " + CACHE_URL_COL
- + " TEXT, " + CACHE_FILE_PATH_COL + " TEXT, "
- + CACHE_LAST_MODIFY_COL + " TEXT, " + CACHE_ETAG_COL
- + " TEXT, " + CACHE_EXPIRES_COL + " INTEGER, "
- + CACHE_MIMETYPE_COL + " TEXT, " + CACHE_ENCODING_COL
- + " TEXT," + CACHE_HTTP_STATUS_COL + " INTEGER, "
- + CACHE_LOCATION_COL + " TEXT, " + CACHE_CONTENTLENGTH_COL
- + " INTEGER, " + " UNIQUE (" + CACHE_URL_COL
- + ") ON CONFLICT REPLACE);");
- mCacheDatabase.execSQL("CREATE INDEX cacheUrlIndex ON cache ("
- + CACHE_URL_COL + ")");
- }
- }
-
- private boolean hasEntries(int tableId) {
- if (mDatabase == null) {
- return false;
- }
-
- Cursor cursor = mDatabase.query(mTableNames[tableId], ID_PROJECTION,
- null, null, null, null, null);
- boolean ret = cursor.moveToFirst() == true;
- cursor.close();
- return ret;
- }
-
- //
- // cookies functions
- //
-
- /**
- * Get cookies in the format of CookieManager.Cookie inside an ArrayList for
- * a given domain
- *
- * @return ArrayList<Cookie> If nothing is found, return an empty list.
- */
- ArrayList<Cookie> getCookiesForDomain(String domain) {
- ArrayList<Cookie> list = new ArrayList<Cookie>();
- if (domain == null || mDatabase == null) {
- return list;
- }
-
- synchronized (mCookieLock) {
- final String[] columns = new String[] {
- ID_COL, COOKIES_DOMAIN_COL, COOKIES_PATH_COL,
- COOKIES_NAME_COL, COOKIES_VALUE_COL, COOKIES_EXPIRES_COL,
- COOKIES_SECURE_COL
- };
- final String selection = "(" + COOKIES_DOMAIN_COL
- + " GLOB '*' || ?)";
- Cursor cursor = mDatabase.query(mTableNames[TABLE_COOKIES_ID],
- columns, selection, new String[] { domain }, null, null,
- null);
- if (cursor.moveToFirst()) {
- int domainCol = cursor.getColumnIndex(COOKIES_DOMAIN_COL);
- int pathCol = cursor.getColumnIndex(COOKIES_PATH_COL);
- int nameCol = cursor.getColumnIndex(COOKIES_NAME_COL);
- int valueCol = cursor.getColumnIndex(COOKIES_VALUE_COL);
- int expiresCol = cursor.getColumnIndex(COOKIES_EXPIRES_COL);
- int secureCol = cursor.getColumnIndex(COOKIES_SECURE_COL);
- do {
- Cookie cookie = new Cookie();
- cookie.domain = cursor.getString(domainCol);
- cookie.path = cursor.getString(pathCol);
- cookie.name = cursor.getString(nameCol);
- cookie.value = cursor.getString(valueCol);
- if (cursor.isNull(expiresCol)) {
- cookie.expires = -1;
- } else {
- cookie.expires = cursor.getLong(expiresCol);
- }
- cookie.secure = cursor.getShort(secureCol) != 0;
- cookie.mode = Cookie.MODE_NORMAL;
- list.add(cookie);
- } while (cursor.moveToNext());
- }
- cursor.close();
- return list;
- }
- }
-
- /**
- * Delete cookies which matches (domain, path, name).
- *
- * @param domain If it is null, nothing happens.
- * @param path If it is null, all the cookies match (domain) will be
- * deleted.
- * @param name If it is null, all the cookies match (domain, path) will be
- * deleted.
- */
- void deleteCookies(String domain, String path, String name) {
- if (domain == null || mDatabase == null) {
- return;
- }
-
- synchronized (mCookieLock) {
- final String where = "(" + COOKIES_DOMAIN_COL + " == ?) AND ("
- + COOKIES_PATH_COL + " == ?) AND (" + COOKIES_NAME_COL
- + " == ?)";
- mDatabase.delete(mTableNames[TABLE_COOKIES_ID], where,
- new String[] { domain, path, name });
- }
- }
-
- /**
- * Add a cookie to the database
- *
- * @param cookie
- */
- void addCookie(Cookie cookie) {
- if (cookie.domain == null || cookie.path == null || cookie.name == null
- || mDatabase == null) {
- return;
- }
-
- synchronized (mCookieLock) {
- ContentValues cookieVal = new ContentValues();
- cookieVal.put(COOKIES_DOMAIN_COL, cookie.domain);
- cookieVal.put(COOKIES_PATH_COL, cookie.path);
- cookieVal.put(COOKIES_NAME_COL, cookie.name);
- cookieVal.put(COOKIES_VALUE_COL, cookie.value);
- if (cookie.expires != -1) {
- cookieVal.put(COOKIES_EXPIRES_COL, cookie.expires);
- }
- cookieVal.put(COOKIES_SECURE_COL, cookie.secure);
- mDatabase.insert(mTableNames[TABLE_COOKIES_ID], null, cookieVal);
- }
- }
-
- /**
- * Whether there is any cookies in the database
- *
- * @return TRUE if there is cookie.
- */
- boolean hasCookies() {
- synchronized (mCookieLock) {
- return hasEntries(TABLE_COOKIES_ID);
- }
- }
-
- /**
- * Clear cookie database
- */
- void clearCookies() {
- if (mDatabase == null) {
- return;
- }
-
- synchronized (mCookieLock) {
- mDatabase.delete(mTableNames[TABLE_COOKIES_ID], null, null);
- }
- }
-
- /**
- * Clear session cookies, which means cookie doesn't have EXPIRES.
- */
- void clearSessionCookies() {
- if (mDatabase == null) {
- return;
- }
-
- final String sessionExpired = COOKIES_EXPIRES_COL + " ISNULL";
- synchronized (mCookieLock) {
- mDatabase.delete(mTableNames[TABLE_COOKIES_ID], sessionExpired,
- null);
- }
- }
-
- /**
- * Clear expired cookies
- *
- * @param now Time for now
- */
- void clearExpiredCookies(long now) {
- if (mDatabase == null) {
- return;
- }
-
- final String expires = COOKIES_EXPIRES_COL + " <= ?";
- synchronized (mCookieLock) {
- mDatabase.delete(mTableNames[TABLE_COOKIES_ID], expires,
- new String[] { Long.toString(now) });
- }
- }
-
- //
- // cache functions, can only be called from WebCoreThread
- //
-
- boolean startCacheTransaction() {
- if (++mCacheTransactionRefcount == 1) {
- mCacheDatabase.beginTransaction();
- return true;
- }
- return false;
- }
-
- boolean endCacheTransaction() {
- if (--mCacheTransactionRefcount == 0) {
- try {
- mCacheDatabase.setTransactionSuccessful();
- } finally {
- mCacheDatabase.endTransaction();
- }
- return true;
- }
- return false;
- }
-
- /**
- * Get a cache item.
- *
- * @param url The url
- * @return CacheResult The CacheManager.CacheResult
- */
- CacheResult getCache(String url) {
- if (url == null || mCacheDatabase == null) {
- return null;
- }
-
- Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath, lastmodify, etag, expires, "
- + "mimetype, encoding, httpstatus, location, contentlength "
- + "FROM cache WHERE url = ?",
- new String[] { url });
-
- try {
- if (cursor.moveToFirst()) {
- CacheResult ret = new CacheResult();
- ret.localPath = cursor.getString(0);
- ret.lastModified = cursor.getString(1);
- ret.etag = cursor.getString(2);
- ret.expires = cursor.getLong(3);
- ret.mimeType = cursor.getString(4);
- ret.encoding = cursor.getString(5);
- ret.httpStatusCode = cursor.getInt(6);
- ret.location = cursor.getString(7);
- ret.contentLength = cursor.getLong(8);
- return ret;
- }
- } finally {
- if (cursor != null) cursor.close();
- }
- return null;
- }
-
- /**
- * Remove a cache item.
- *
- * @param url The url
- */
- void removeCache(String url) {
- if (url == null || mCacheDatabase == null) {
- return;
- }
-
- mCacheDatabase.execSQL("DELETE FROM cache WHERE url = ?", new String[] { url });
- }
-
- /**
- * Add or update a cache. CACHE_URL_COL is unique in the table.
- *
- * @param url The url
- * @param c The CacheManager.CacheResult
- */
- void addCache(String url, CacheResult c) {
- if (url == null || mCacheDatabase == null) {
- return;
- }
-
- mCacheInserter.prepareForInsert();
- mCacheInserter.bind(mCacheUrlColIndex, url);
- mCacheInserter.bind(mCacheFilePathColIndex, c.localPath);
- mCacheInserter.bind(mCacheLastModifyColIndex, c.lastModified);
- mCacheInserter.bind(mCacheETagColIndex, c.etag);
- mCacheInserter.bind(mCacheExpiresColIndex, c.expires);
- mCacheInserter.bind(mCacheMimeTypeColIndex, c.mimeType);
- mCacheInserter.bind(mCacheEncodingColIndex, c.encoding);
- mCacheInserter.bind(mCacheHttpStatusColIndex, c.httpStatusCode);
- mCacheInserter.bind(mCacheLocationColIndex, c.location);
- mCacheInserter.bind(mCacheContentLengthColIndex, c.contentLength);
- mCacheInserter.execute();
- }
-
- /**
- * Clear cache database
- */
- void clearCache() {
- if (mCacheDatabase == null) {
- return;
- }
-
- mCacheDatabase.delete("cache", null, null);
- }
-
- boolean hasCache() {
- if (mCacheDatabase == null) {
- return false;
- }
-
- Cursor cursor = mCacheDatabase.query("cache", ID_PROJECTION,
- null, null, null, null, null);
- boolean ret = cursor.moveToFirst() == true;
- cursor.close();
- return ret;
- }
-
- long getCacheTotalSize() {
- long size = 0;
- Cursor cursor = mCacheDatabase.rawQuery(
- "SELECT SUM(contentlength) as sum FROM cache", null);
- if (cursor.moveToFirst()) {
- size = cursor.getLong(0);
- }
- cursor.close();
- return size;
- }
-
- ArrayList<String> trimCache(long amount) {
- ArrayList<String> pathList = new ArrayList<String>(100);
- Cursor cursor = mCacheDatabase.rawQuery(
- "SELECT contentlength, filepath FROM cache ORDER BY expires ASC",
- null);
- if (cursor.moveToFirst()) {
- int batchSize = 100;
- StringBuilder pathStr = new StringBuilder(20 + 16 * batchSize);
- pathStr.append("DELETE FROM cache WHERE filepath IN (?");
- for (int i = 1; i < batchSize; i++) {
- pathStr.append(", ?");
- }
- pathStr.append(")");
- SQLiteStatement statement = mCacheDatabase.compileStatement(pathStr
- .toString());
- // as bindString() uses 1-based index, initialize index to 1
- int index = 1;
- do {
- long length = cursor.getLong(0);
- if (length == 0) {
- continue;
- }
- amount -= length;
- String filePath = cursor.getString(1);
- statement.bindString(index, filePath);
- pathList.add(filePath);
- if (index++ == batchSize) {
- statement.execute();
- statement.clearBindings();
- index = 1;
- }
- } while (cursor.moveToNext() && amount > 0);
- if (index > 1) {
- // there may be old bindings from the previous statement if
- // index is less than batchSize, which is Ok.
- statement.execute();
- }
- statement.close();
- }
- cursor.close();
- return pathList;
- }
-
- //
- // password functions
- //
-
- /**
- * Set password. Tuple (PASSWORD_HOST_COL, PASSWORD_USERNAME_COL) is unique.
- *
- * @param schemePlusHost The scheme and host for the password
- * @param username The username for the password. If it is null, it means
- * password can't be saved.
- * @param password The password
- */
- void setUsernamePassword(String schemePlusHost, String username,
- String password) {
- if (schemePlusHost == null || mDatabase == null) {
- return;
- }
-
- synchronized (mPasswordLock) {
- final ContentValues c = new ContentValues();
- c.put(PASSWORD_HOST_COL, schemePlusHost);
- c.put(PASSWORD_USERNAME_COL, username);
- c.put(PASSWORD_PASSWORD_COL, password);
- mDatabase.insert(mTableNames[TABLE_PASSWORD_ID], PASSWORD_HOST_COL,
- c);
- }
- }
-
- /**
- * Retrieve the username and password for a given host
- *
- * @param schemePlusHost The scheme and host which passwords applies to
- * @return String[] if found, String[0] is username, which can be null and
- * String[1] is password. Return null if it can't find anything.
- */
- String[] getUsernamePassword(String schemePlusHost) {
- if (schemePlusHost == null || mDatabase == null) {
- return null;
- }
-
- final String[] columns = new String[] {
- PASSWORD_USERNAME_COL, PASSWORD_PASSWORD_COL
- };
- final String selection = "(" + PASSWORD_HOST_COL + " == ?)";
- synchronized (mPasswordLock) {
- String[] ret = null;
- Cursor cursor = mDatabase.query(mTableNames[TABLE_PASSWORD_ID],
- columns, selection, new String[] { schemePlusHost }, null,
- null, null);
- if (cursor.moveToFirst()) {
- ret = new String[2];
- ret[0] = cursor.getString(
- cursor.getColumnIndex(PASSWORD_USERNAME_COL));
- ret[1] = cursor.getString(
- cursor.getColumnIndex(PASSWORD_PASSWORD_COL));
- }
- cursor.close();
- return ret;
- }
- }
-
- /**
- * Find out if there are any passwords saved.
- *
- * @return TRUE if there is passwords saved
- */
- public boolean hasUsernamePassword() {
- synchronized (mPasswordLock) {
- return hasEntries(TABLE_PASSWORD_ID);
- }
- }
-
- /**
- * Clear password database
- */
- public void clearUsernamePassword() {
- if (mDatabase == null) {
- return;
- }
-
- synchronized (mPasswordLock) {
- mDatabase.delete(mTableNames[TABLE_PASSWORD_ID], null, null);
- }
- }
-
- //
- // http authentication password functions
- //
-
- /**
- * Set HTTP authentication password. Tuple (HTTPAUTH_HOST_COL,
- * HTTPAUTH_REALM_COL, HTTPAUTH_USERNAME_COL) is unique.
- *
- * @param host The host for the password
- * @param realm The realm for the password
- * @param username The username for the password. If it is null, it means
- * password can't be saved.
- * @param password The password
- */
- void setHttpAuthUsernamePassword(String host, String realm, String username,
- String password) {
- if (host == null || realm == null || mDatabase == null) {
- return;
- }
-
- synchronized (mHttpAuthLock) {
- final ContentValues c = new ContentValues();
- c.put(HTTPAUTH_HOST_COL, host);
- c.put(HTTPAUTH_REALM_COL, realm);
- c.put(HTTPAUTH_USERNAME_COL, username);
- c.put(HTTPAUTH_PASSWORD_COL, password);
- mDatabase.insert(mTableNames[TABLE_HTTPAUTH_ID], HTTPAUTH_HOST_COL,
- c);
- }
- }
-
- /**
- * Retrieve the HTTP authentication username and password for a given
- * host+realm pair
- *
- * @param host The host the password applies to
- * @param realm The realm the password applies to
- * @return String[] if found, String[0] is username, which can be null and
- * String[1] is password. Return null if it can't find anything.
- */
- String[] getHttpAuthUsernamePassword(String host, String realm) {
- if (host == null || realm == null || mDatabase == null){
- return null;
- }
-
- final String[] columns = new String[] {
- HTTPAUTH_USERNAME_COL, HTTPAUTH_PASSWORD_COL
- };
- final String selection = "(" + HTTPAUTH_HOST_COL + " == ?) AND ("
- + HTTPAUTH_REALM_COL + " == ?)";
- synchronized (mHttpAuthLock) {
- String[] ret = null;
- Cursor cursor = mDatabase.query(mTableNames[TABLE_HTTPAUTH_ID],
- columns, selection, new String[] { host, realm }, null,
- null, null);
- if (cursor.moveToFirst()) {
- ret = new String[2];
- ret[0] = cursor.getString(
- cursor.getColumnIndex(HTTPAUTH_USERNAME_COL));
- ret[1] = cursor.getString(
- cursor.getColumnIndex(HTTPAUTH_PASSWORD_COL));
- }
- cursor.close();
- return ret;
- }
- }
-
- /**
- * Find out if there are any HTTP authentication passwords saved.
- *
- * @return TRUE if there are passwords saved
- */
- public boolean hasHttpAuthUsernamePassword() {
- synchronized (mHttpAuthLock) {
- return hasEntries(TABLE_HTTPAUTH_ID);
- }
- }
-
- /**
- * Clear HTTP authentication password database
- */
- public void clearHttpAuthUsernamePassword() {
- if (mDatabase == null) {
- return;
- }
-
- synchronized (mHttpAuthLock) {
- mDatabase.delete(mTableNames[TABLE_HTTPAUTH_ID], null, null);
- }
- }
-
- //
- // form data functions
- //
-
- /**
- * Set form data for a site. Tuple (FORMDATA_URLID_COL, FORMDATA_NAME_COL,
- * FORMDATA_VALUE_COL) is unique
- *
- * @param url The url of the site
- * @param formdata The form data in HashMap
- */
- void setFormData(String url, HashMap<String, String> formdata) {
- if (url == null || formdata == null || mDatabase == null) {
- return;
- }
-
- final String selection = "(" + FORMURL_URL_COL + " == ?)";
- synchronized (mFormLock) {
- long urlid = -1;
- Cursor cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID],
- ID_PROJECTION, selection, new String[] { url }, null, null,
- null);
- if (cursor.moveToFirst()) {
- urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
- } else {
- ContentValues c = new ContentValues();
- c.put(FORMURL_URL_COL, url);
- urlid = mDatabase.insert(
- mTableNames[TABLE_FORMURL_ID], null, c);
- }
- cursor.close();
- if (urlid >= 0) {
- Set<Entry<String, String>> set = formdata.entrySet();
- Iterator<Entry<String, String>> iter = set.iterator();
- ContentValues map = new ContentValues();
- map.put(FORMDATA_URLID_COL, urlid);
- while (iter.hasNext()) {
- Entry<String, String> entry = iter.next();
- map.put(FORMDATA_NAME_COL, entry.getKey());
- map.put(FORMDATA_VALUE_COL, entry.getValue());
- mDatabase.insert(mTableNames[TABLE_FORMDATA_ID], null, map);
- }
- }
- }
- }
-
- /**
- * Get all the values for a form entry with "name" in a given site
- *
- * @param url The url of the site
- * @param name The name of the form entry
- * @return A list of values. Return empty list if nothing is found.
- */
- ArrayList<String> getFormData(String url, String name) {
- ArrayList<String> values = new ArrayList<String>();
- if (url == null || name == null || mDatabase == null) {
- return values;
- }
-
- final String urlSelection = "(" + FORMURL_URL_COL + " == ?)";
- final String dataSelection = "(" + FORMDATA_URLID_COL + " == ?) AND ("
- + FORMDATA_NAME_COL + " == ?)";
- synchronized (mFormLock) {
- Cursor cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID],
- ID_PROJECTION, urlSelection, new String[] { url }, null,
- null, null);
- if (cursor.moveToFirst()) {
- long urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
- Cursor dataCursor = mDatabase.query(
- mTableNames[TABLE_FORMDATA_ID],
- new String[] { ID_COL, FORMDATA_VALUE_COL },
- dataSelection,
- new String[] { Long.toString(urlid), name }, null,
- null, null);
- if (dataCursor.moveToFirst()) {
- int valueCol =
- dataCursor.getColumnIndex(FORMDATA_VALUE_COL);
- do {
- values.add(dataCursor.getString(valueCol));
- } while (dataCursor.moveToNext());
- }
- dataCursor.close();
- }
- cursor.close();
- return values;
- }
- }
-
- /**
- * Find out if there is form data saved.
- *
- * @return TRUE if there is form data in the database
- */
- public boolean hasFormData() {
- synchronized (mFormLock) {
- return hasEntries(TABLE_FORMURL_ID);
- }
- }
-
- /**
- * Clear form database
- */
- public void clearFormData() {
- if (mDatabase == null) {
- return;
- }
-
- synchronized (mFormLock) {
- mDatabase.delete(mTableNames[TABLE_FORMURL_ID], null, null);
- mDatabase.delete(mTableNames[TABLE_FORMDATA_ID], null, null);
- }
- }
-}
diff --git a/core/java/android/webkit/gears/AndroidGpsLocationProvider.java b/core/java/android/webkit/gears/AndroidGpsLocationProvider.java
deleted file mode 100644
index 3646042..0000000
--- a/core/java/android/webkit/gears/AndroidGpsLocationProvider.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
-import android.os.Bundle;
-import android.util.Log;
-import android.webkit.WebView;
-
-/**
- * GPS provider implementation for Android.
- */
-public final class AndroidGpsLocationProvider implements LocationListener {
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-GpsProvider";
- /**
- * Our location manager instance.
- */
- private LocationManager locationManager;
- /**
- * The native object ID.
- */
- private long nativeObject;
-
- public AndroidGpsLocationProvider(WebView webview, long object) {
- nativeObject = object;
- locationManager = (LocationManager) webview.getContext().getSystemService(
- Context.LOCATION_SERVICE);
- if (locationManager == null) {
- Log.e(TAG,
- "AndroidGpsLocationProvider: could not get location manager.");
- throw new NullPointerException(
- "AndroidGpsLocationProvider: locationManager is null.");
- }
- // Register for location updates.
- try {
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
- this);
- } catch (IllegalArgumentException ex) {
- Log.e(TAG,
- "AndroidLocationGpsProvider: could not register for updates: " + ex);
- throw ex;
- } catch (SecurityException ex) {
- Log.e(TAG,
- "AndroidGpsLocationProvider: not allowed to register for update: "
- + ex);
- throw ex;
- }
- }
-
- /**
- * Called when the provider is no longer needed.
- */
- public void shutdown() {
- locationManager.removeUpdates(this);
- Log.i(TAG, "GPS provider closed.");
- }
-
- /**
- * Called when the location has changed.
- * @param location The new location, as a Location object.
- */
- public void onLocationChanged(Location location) {
- Log.i(TAG, "Location changed: " + location);
- nativeLocationChanged(location, nativeObject);
- }
-
- /**
- * Called when the provider status changes.
- *
- * @param provider the name of the location provider associated with this
- * update.
- * @param status {@link LocationProvider#OUT_OF_SERVICE} if the
- * provider is out of service, and this is not expected to change in the
- * near future; {@link LocationProvider#TEMPORARILY_UNAVAILABLE} if
- * the provider is temporarily unavailable but is expected to be available
- * shortly; and {@link LocationProvider#AVAILABLE} if the
- * provider is currently available.
- * @param extras an optional Bundle which will contain provider specific
- * status variables (such as number of satellites).
- */
- public void onStatusChanged(String provider, int status, Bundle extras) {
- Log.i(TAG, "Provider " + provider + " status changed to " + status);
- if (status == LocationProvider.OUT_OF_SERVICE ||
- status == LocationProvider.TEMPORARILY_UNAVAILABLE) {
- nativeProviderError(false, nativeObject);
- }
- }
-
- /**
- * Called when the provider is enabled.
- *
- * @param provider the name of the location provider that is now enabled.
- */
- public void onProviderEnabled(String provider) {
- Log.i(TAG, "Provider " + provider + " enabled.");
- // No need to notify the native side. It's enough to start sending
- // valid position fixes again.
- }
-
- /**
- * Called when the provider is disabled.
- *
- * @param provider the name of the location provider that is now disabled.
- */
- public void onProviderDisabled(String provider) {
- Log.i(TAG, "Provider " + provider + " disabled.");
- nativeProviderError(true, nativeObject);
- }
-
- /**
- * The native method called when a new location is available.
- * @param location is the new Location instance to pass to the native side.
- * @param nativeObject is a pointer to the corresponding
- * AndroidGpsLocationProvider C++ instance.
- */
- private native void nativeLocationChanged(Location location, long object);
-
- /**
- * The native method called when there is a GPS provder error.
- * @param isDisabled is true when the error signifies the fact that the GPS
- * HW is disabled. For other errors, this param is always false.
- * @param nativeObject is a pointer to the corresponding
- * AndroidGpsLocationProvider C++ instance.
- */
- private native void nativeProviderError(boolean isDisabled, long object);
-}
diff --git a/core/java/android/webkit/gears/AndroidRadioDataProvider.java b/core/java/android/webkit/gears/AndroidRadioDataProvider.java
deleted file mode 100644
index c920d45..0000000
--- a/core/java/android/webkit/gears/AndroidRadioDataProvider.java
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.telephony.CellLocation;
-import android.telephony.ServiceState;
-import android.telephony.gsm.GsmCellLocation;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.webkit.WebView;
-
-/**
- * Radio data provider implementation for Android.
- */
-public final class AndroidRadioDataProvider extends PhoneStateListener {
-
- /** Logging tag */
- private static final String TAG = "Gears-J-RadioProvider";
-
- /** Network types */
- private static final int RADIO_TYPE_UNKNOWN = 0;
- private static final int RADIO_TYPE_GSM = 1;
- private static final int RADIO_TYPE_WCDMA = 2;
-
- /** Simple container for radio data */
- public static final class RadioData {
- public int cellId = -1;
- public int locationAreaCode = -1;
- public int signalStrength = -1;
- public int mobileCountryCode = -1;
- public int mobileNetworkCode = -1;
- public int homeMobileCountryCode = -1;
- public int homeMobileNetworkCode = -1;
- public int radioType = RADIO_TYPE_UNKNOWN;
- public String carrierName;
-
- /**
- * Constructs radioData object from the given telephony data.
- * @param telephonyManager contains the TelephonyManager instance.
- * @param cellLocation contains information about the current GSM cell.
- * @param signalStrength is the strength of the network signal.
- * @param serviceState contains information about the network service.
- * @return a new RadioData object populated with the currently
- * available network information or null if there isn't
- * enough information.
- */
- public static RadioData getInstance(TelephonyManager telephonyManager,
- CellLocation cellLocation, int signalStrength,
- ServiceState serviceState) {
-
- if (!(cellLocation instanceof GsmCellLocation)) {
- // This also covers the case when cellLocation is null.
- // When that happens, we do not bother creating a
- // RadioData instance.
- return null;
- }
-
- RadioData radioData = new RadioData();
- GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
-
- // Extract the cell id, LAC, and signal strength.
- radioData.cellId = gsmCellLocation.getCid();
- radioData.locationAreaCode = gsmCellLocation.getLac();
- radioData.signalStrength = signalStrength;
-
- // Extract the home MCC and home MNC.
- String operator = telephonyManager.getSimOperator();
- radioData.setMobileCodes(operator, true);
-
- if (serviceState != null) {
- // Extract the carrier name.
- radioData.carrierName = serviceState.getOperatorAlphaLong();
-
- // Extract the MCC and MNC.
- operator = serviceState.getOperatorNumeric();
- radioData.setMobileCodes(operator, false);
- }
-
- // Finally get the radio type.
- int type = telephonyManager.getNetworkType();
- if (type == TelephonyManager.NETWORK_TYPE_UMTS) {
- radioData.radioType = RADIO_TYPE_WCDMA;
- } else if (type == TelephonyManager.NETWORK_TYPE_GPRS
- || type == TelephonyManager.NETWORK_TYPE_EDGE) {
- radioData.radioType = RADIO_TYPE_GSM;
- }
-
- // Print out what we got.
- Log.i(TAG, "Got the following data:");
- Log.i(TAG, "CellId: " + radioData.cellId);
- Log.i(TAG, "LAC: " + radioData.locationAreaCode);
- Log.i(TAG, "MNC: " + radioData.mobileNetworkCode);
- Log.i(TAG, "MCC: " + radioData.mobileCountryCode);
- Log.i(TAG, "home MNC: " + radioData.homeMobileNetworkCode);
- Log.i(TAG, "home MCC: " + radioData.homeMobileCountryCode);
- Log.i(TAG, "Signal strength: " + radioData.signalStrength);
- Log.i(TAG, "Carrier: " + radioData.carrierName);
- Log.i(TAG, "Network type: " + radioData.radioType);
-
- return radioData;
- }
-
- private RadioData() {}
-
- /**
- * Parses a string containing a mobile country code and a mobile
- * network code and sets the corresponding member variables.
- * @param codes is the string to parse.
- * @param homeValues flags whether the codes are for the home operator.
- */
- private void setMobileCodes(String codes, boolean homeValues) {
- if (codes != null) {
- try {
- // The operator numeric format is 3 digit country code plus 2 or
- // 3 digit network code.
- int mcc = Integer.parseInt(codes.substring(0, 3));
- int mnc = Integer.parseInt(codes.substring(3));
- if (homeValues) {
- homeMobileCountryCode = mcc;
- homeMobileNetworkCode = mnc;
- } else {
- mobileCountryCode = mcc;
- mobileNetworkCode = mnc;
- }
- } catch (IndexOutOfBoundsException ex) {
- Log.e(
- TAG,
- "AndroidRadioDataProvider: Invalid operator numeric data: " + ex);
- } catch (NumberFormatException ex) {
- Log.e(
- TAG,
- "AndroidRadioDataProvider: Operator numeric format error: " + ex);
- }
- }
- }
- };
-
- /** The native object ID */
- private long nativeObject;
-
- /** The last known cellLocation */
- private CellLocation cellLocation = null;
-
- /** The last known signal strength */
- private int signalStrength = -1;
-
- /** The last known serviceState */
- private ServiceState serviceState = null;
-
- /**
- * Our TelephonyManager instance.
- */
- private TelephonyManager telephonyManager;
-
- /**
- * Public constructor. Uses the webview to get the Context object.
- */
- public AndroidRadioDataProvider(WebView webview, long object) {
- super();
- nativeObject = object;
- telephonyManager = (TelephonyManager) webview.getContext().getSystemService(
- Context.TELEPHONY_SERVICE);
- if (telephonyManager == null) {
- Log.e(TAG,
- "AndroidRadioDataProvider: could not get tepephony manager.");
- throw new NullPointerException(
- "AndroidRadioDataProvider: telephonyManager is null.");
- }
-
- // Register for cell id, signal strength and service state changed
- // notifications.
- telephonyManager.listen(this, PhoneStateListener.LISTEN_CELL_LOCATION
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTH
- | PhoneStateListener.LISTEN_SERVICE_STATE);
- }
-
- /**
- * Should be called when the provider is no longer needed.
- */
- public void shutdown() {
- telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
- Log.i(TAG, "AndroidRadioDataProvider shutdown.");
- }
-
- @Override
- public void onServiceStateChanged(ServiceState state) {
- serviceState = state;
- notifyListeners();
- }
-
- @Override
- public void onSignalStrengthChanged(int asu) {
- signalStrength = asu;
- notifyListeners();
- }
-
- @Override
- public void onCellLocationChanged(CellLocation location) {
- cellLocation = location;
- notifyListeners();
- }
-
- private void notifyListeners() {
- RadioData radioData = RadioData.getInstance(telephonyManager, cellLocation,
- signalStrength, serviceState);
- if (radioData != null) {
- onUpdateAvailable(radioData, nativeObject);
- }
- }
-
- /**
- * The native method called when new radio data is available.
- * @param radioData is the RadioData instance to pass to the native side.
- * @param nativeObject is a pointer to the corresponding
- * AndroidRadioDataProvider C++ instance.
- */
- private static native void onUpdateAvailable(
- RadioData radioData, long nativeObject);
-}
diff --git a/core/java/android/webkit/gears/AndroidWifiDataProvider.java b/core/java/android/webkit/gears/AndroidWifiDataProvider.java
deleted file mode 100644
index 7379f59..0000000
--- a/core/java/android/webkit/gears/AndroidWifiDataProvider.java
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2008, Google Inc.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Config;
-import android.util.Log;
-import android.webkit.WebView;
-import java.util.List;
-
-/**
- * WiFi data provider implementation for Android.
- * {@hide}
- */
-public final class AndroidWifiDataProvider extends BroadcastReceiver {
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-WifiProvider";
- /**
- * Our Wifi manager instance.
- */
- private WifiManager mWifiManager;
- /**
- * The native object ID.
- */
- private long mNativeObject;
- /**
- * The Context instance.
- */
- private Context mContext;
-
- /**
- * Constructs a instance of this class and registers for wifi scan
- * updates. Note that this constructor must be called on a Looper
- * thread. Suitable threads can be created on the native side using
- * the AndroidLooperThread C++ class.
- */
- public AndroidWifiDataProvider(WebView webview, long object) {
- mNativeObject = object;
- mContext = webview.getContext();
- mWifiManager =
- (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- if (mWifiManager == null) {
- Log.e(TAG,
- "AndroidWifiDataProvider: could not get location manager.");
- throw new NullPointerException(
- "AndroidWifiDataProvider: locationManager is null.");
- }
-
- // Create a Handler that identifies the message loop associated
- // with the current thread. Note that it is not necessary to
- // override handleMessage() at all since the Intent
- // ReceiverDispatcher (see the ActivityThread class) only uses
- // this handler to post a Runnable to this thread's loop.
- Handler handler = new Handler(Looper.myLooper());
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
- mContext.registerReceiver(this, filter, null, handler);
-
- // Get the last scan results and pass them to the native side.
- // We can't just invoke the callback here, so we queue a message
- // to this thread's loop.
- handler.post(new Runnable() {
- public void run() {
- onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
- }
- });
- }
-
- /**
- * Called when the provider is no longer needed.
- */
- public void shutdown() {
- mContext.unregisterReceiver(this);
- if (Config.LOGV) {
- Log.v(TAG, "Wifi provider closed.");
- }
- }
-
- /**
- * This method is called when the AndroidWifiDataProvider is receiving an
- * Intent broadcast.
- * @param context The Context in which the receiver is running.
- * @param intent The Intent being received.
- */
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(
- mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- if (Config.LOGV) {
- Log.v(TAG, "Wifi scan resulst available");
- }
- onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
- }
- }
-
- /**
- * The native method called when new wifi data is available.
- * @param scanResults is a list of ScanResults to pass to the native side.
- * @param nativeObject is a pointer to the corresponding
- * AndroidWifiDataProvider C++ instance.
- */
- private static native void onUpdateAvailable(
- List<ScanResult> scanResults, long nativeObject);
-}
diff --git a/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java b/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
deleted file mode 100644
index 0569255..0000000
--- a/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
+++ /dev/null
@@ -1,1122 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.net.http.Headers;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Config;
-import android.util.Log;
-import android.webkit.CacheManager;
-import android.webkit.CacheManager.CacheResult;
-import android.webkit.CookieManager;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.IOException;
-import java.lang.StringBuilder;
-import java.util.Date;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Iterator;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.HttpResponse;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.client.*;
-import org.apache.http.client.methods.*;
-import org.apache.http.impl.client.AbstractHttpClient;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
-import org.apache.http.conn.ssl.StrictHostnameVerifier;
-import org.apache.http.impl.cookie.DateUtils;
-import org.apache.http.util.CharArrayBuffer;
-
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Performs the underlying HTTP/HTTPS GET, POST, HEAD, PUT, DELETE requests.
- * <p> These are performed synchronously (blocking). The caller should
- * ensure that it is in a background thread if asynchronous behavior
- * is required. All data is pushed, so there is no need for JNI native
- * callbacks.
- * <p> This uses Apache's HttpClient framework to perform most
- * of the underlying network activity. The Android brower's cache,
- * android.webkit.CacheManager, is also used when caching is enabled,
- * and updated with new data. The android.webkit.CookieManager is also
- * queried and updated as necessary.
- * <p> The public interface is designed to be called by native code
- * through JNI, and to simplify coding none of the public methods will
- * surface a checked exception. Unchecked exceptions may still be
- * raised but only if the system is in an ill state, such as out of
- * memory.
- * <p> TODO: This isn't plumbed into LocalServer yet. Mutually
- * dependent on LocalServer - will attach the two together once both
- * are submitted.
- */
-public final class ApacheHttpRequestAndroid {
- /** Debug logging tag. */
- private static final String LOG_TAG = "Gears-J";
- /** HTTP response header line endings are CR-LF style. */
- private static final String HTTP_LINE_ENDING = "\r\n";
- /** Safe MIME type to use whenever it isn't specified. */
- private static final String DEFAULT_MIME_TYPE = "text/plain";
- /** Case-sensitive header keys */
- public static final String KEY_CONTENT_LENGTH = "Content-Length";
- public static final String KEY_EXPIRES = "Expires";
- public static final String KEY_LAST_MODIFIED = "Last-Modified";
- public static final String KEY_ETAG = "ETag";
- public static final String KEY_LOCATION = "Location";
- public static final String KEY_CONTENT_TYPE = "Content-Type";
- /** Number of bytes to send and receive on the HTTP connection in
- * one go. */
- private static final int BUFFER_SIZE = 4096;
-
- /** The first element of the String[] value in a headers map is the
- * unmodified (case-sensitive) key. */
- public static final int HEADERS_MAP_INDEX_KEY = 0;
- /** The second element of the String[] value in a headers map is the
- * associated value. */
- public static final int HEADERS_MAP_INDEX_VALUE = 1;
-
- /** Request headers, as key -> value map. */
- // TODO: replace this design by a simpler one (the C++ side has to
- // be modified too), where we do not store both the original header
- // and the lowercase one.
- private Map<String, String[]> mRequestHeaders =
- new HashMap<String, String[]>();
- /** Response headers, as a lowercase key -> value map. */
- private Map<String, String[]> mResponseHeaders =
- new HashMap<String, String[]>();
- /** The URL used for createCacheResult() */
- private String mCacheResultUrl;
- /** CacheResult being saved into, if inserting a new cache entry. */
- private CacheResult mCacheResult;
- /** Initialized by initChildThread(). Used to target abort(). */
- private Thread mBridgeThread;
-
- /** Our HttpClient */
- private AbstractHttpClient mClient;
- /** The HttpMethod associated with this request */
- private HttpRequestBase mMethod;
- /** The complete response line e.g "HTTP/1.0 200 OK" */
- private String mResponseLine;
- /** HTTP body stream, setup after connection. */
- private InputStream mBodyInputStream;
-
- /** HTTP Response Entity */
- private HttpResponse mResponse;
-
- /** Post Entity, used to stream the request to the server */
- private StreamEntity mPostEntity = null;
- /** Content lenght, mandatory when using POST */
- private long mContentLength;
-
- /** The request executes in a parallel thread */
- private Thread mHttpThread = null;
- /** protect mHttpThread, if interrupt() is called concurrently */
- private Lock mHttpThreadLock = new ReentrantLock();
- /** Flag set to true when the request thread is joined */
- private boolean mConnectionFinished = false;
- /** Flag set to true by interrupt() and/or connection errors */
- private boolean mConnectionFailed = false;
- /** Lock protecting the access to mConnectionFailed */
- private Lock mConnectionFailedLock = new ReentrantLock();
-
- /** Lock on the loop in StreamEntity */
- private Lock mStreamingReadyLock = new ReentrantLock();
- /** Condition variable used to signal the loop is ready... */
- private Condition mStreamingReady = mStreamingReadyLock.newCondition();
-
- /** Used to pass around the block of data POSTed */
- private Buffer mBuffer = new Buffer();
- /** Used to signal that the block of data has been written */
- private SignalConsumed mSignal = new SignalConsumed();
-
- // inner classes
-
- /**
- * Implements the http request
- */
- class Connection implements Runnable {
- public void run() {
- boolean problem = false;
- try {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "REQUEST : " + mMethod.getRequestLine());
- }
- mResponse = mClient.execute(mMethod);
- if (mResponse != null) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "response (status line): "
- + mResponse.getStatusLine());
- }
- mResponseLine = "" + mResponse.getStatusLine();
- } else {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "problem, response == null");
- }
- problem = true;
- }
- } catch (IOException e) {
- Log.e(LOG_TAG, "Connection IO exception ", e);
- problem = true;
- } catch (RuntimeException e) {
- Log.e(LOG_TAG, "Connection runtime exception ", e);
- problem = true;
- }
-
- if (!problem) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Request complete ("
- + mMethod.getRequestLine() + ")");
- }
- } else {
- mConnectionFailedLock.lock();
- mConnectionFailed = true;
- mConnectionFailedLock.unlock();
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Request FAILED ("
- + mMethod.getRequestLine() + ")");
- }
- // We abort the execution in order to shutdown and release
- // the underlying connection
- mMethod.abort();
- if (mPostEntity != null) {
- // If there is a post entity, we need to wake it up from
- // a potential deadlock
- mPostEntity.signalOutputStream();
- }
- }
- }
- }
-
- /**
- * simple buffer class implementing a producer/consumer model
- */
- class Buffer {
- private DataPacket mPacket;
- private boolean mEmpty = true;
- public synchronized void put(DataPacket packet) {
- while (!mEmpty) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "InterruptedException while putting " +
- "a DataPacket in the Buffer: " + e);
- }
- }
- }
- mPacket = packet;
- mEmpty = false;
- notify();
- }
- public synchronized DataPacket get() {
- while (mEmpty) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "InterruptedException while getting " +
- "a DataPacket in the Buffer: " + e);
- }
- }
- }
- mEmpty = true;
- notify();
- return mPacket;
- }
- }
-
- /**
- * utility class used to block until the packet is signaled as being
- * consumed
- */
- class SignalConsumed {
- private boolean mConsumed = false;
- public synchronized void waitUntilPacketConsumed() {
- while (!mConsumed) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "InterruptedException while waiting " +
- "until a DataPacket is consumed: " + e);
- }
- }
- }
- mConsumed = false;
- notify();
- }
- public synchronized void packetConsumed() {
- while (mConsumed) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "InterruptedException while indicating "
- + "that the DataPacket has been consumed: " + e);
- }
- }
- }
- mConsumed = true;
- notify();
- }
- }
-
- /**
- * Utility class encapsulating a packet of data
- */
- class DataPacket {
- private byte[] mContent;
- private int mLength;
- public DataPacket(byte[] content, int length) {
- mContent = content;
- mLength = length;
- }
- public byte[] getBytes() {
- return mContent;
- }
- public int getLength() {
- return mLength;
- }
- }
-
- /**
- * HttpEntity class to write the bytes received by the C++ thread
- * on the connection outputstream, in a streaming way.
- * This entity is executed in the request thread.
- * The writeTo() method is automatically called by the
- * HttpPost execution; upon reception, we loop while receiving
- * the data packets from the main thread, until completion
- * or error. When done, we flush the outputstream.
- * The main thread (sendPostData()) also blocks until the
- * outputstream is made available (or an error happens)
- */
- class StreamEntity implements HttpEntity {
- private OutputStream mOutputStream;
-
- // HttpEntity interface methods
-
- public boolean isRepeatable() {
- return false;
- }
-
- public boolean isChunked() {
- return false;
- }
-
- public long getContentLength() {
- return mContentLength;
- }
-
- public Header getContentType() {
- return null;
- }
-
- public Header getContentEncoding() {
- return null;
- }
-
- public InputStream getContent() throws IOException {
- return null;
- }
-
- public void writeTo(final OutputStream out) throws IOException {
- // We signal that the outputstream is available
- mStreamingReadyLock.lock();
- mOutputStream = out;
- mStreamingReady.signal();
- mStreamingReadyLock.unlock();
-
- // We then loop waiting on messages to process.
- boolean finished = false;
- while (!finished) {
- DataPacket packet = mBuffer.get();
- if (packet == null) {
- finished = true;
- } else {
- write(packet);
- }
- mSignal.packetConsumed();
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "stopping loop on error");
- }
- finished = true;
- }
- mConnectionFailedLock.unlock();
- }
- if (Config.LOGV) {
- Log.i(LOG_TAG, "flushing the outputstream...");
- }
- mOutputStream.flush();
- }
-
- public boolean isStreaming() {
- return true;
- }
-
- public void consumeContent() throws IOException {
- // Nothing to release
- }
-
- // local methods
-
- private void write(DataPacket packet) {
- try {
- if (mOutputStream == null) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "NO OUTPUT STREAM !!!");
- }
- return;
- }
- mOutputStream.write(packet.getBytes(), 0, packet.getLength());
- mOutputStream.flush();
- } catch (IOException e) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "exc: " + e);
- }
- mConnectionFailedLock.lock();
- mConnectionFailed = true;
- mConnectionFailedLock.unlock();
- }
- }
-
- public boolean isReady() {
- mStreamingReadyLock.lock();
- try {
- if (mOutputStream == null) {
- mStreamingReady.await();
- }
- } catch (InterruptedException e) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "InterruptedException in "
- + "StreamEntity::isReady() : ", e);
- }
- } finally {
- mStreamingReadyLock.unlock();
- }
- if (mOutputStream == null) {
- return false;
- }
- return true;
- }
-
- public void signalOutputStream() {
- mStreamingReadyLock.lock();
- mStreamingReady.signal();
- mStreamingReadyLock.unlock();
- }
- }
-
- /**
- * Initialize mBridgeThread using the TLS value of
- * Thread.currentThread(). Called on start up of the native child
- * thread.
- */
- public synchronized void initChildThread() {
- mBridgeThread = Thread.currentThread();
- }
-
- public void setContentLength(long length) {
- mContentLength = length;
- }
-
- /**
- * Analagous to the native-side HttpRequest::open() function. This
- * initializes an underlying HttpClient method, but does
- * not go to the wire. On success, this enables a call to send() to
- * initiate the transaction.
- *
- * @param method The HTTP method, e.g GET or POST.
- * @param url The URL to open.
- * @return True on success with a complete HTTP response.
- * False on failure.
- */
- public synchronized boolean open(String method, String url) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "open " + method + " " + url);
- }
- // Create the client
- if (mConnectionFailed) {
- // interrupt() could have been called even before open()
- return false;
- }
- mClient = new DefaultHttpClient();
- mClient.setHttpRequestRetryHandler(
- new DefaultHttpRequestRetryHandler(0, false));
- mBodyInputStream = null;
- mResponseLine = null;
- mResponseHeaders = null;
- mPostEntity = null;
- mHttpThread = null;
- mConnectionFailed = false;
- mConnectionFinished = false;
-
- // Create the method. We support everything that
- // Apache HttpClient supports, apart from TRACE.
- if ("GET".equalsIgnoreCase(method)) {
- mMethod = new HttpGet(url);
- } else if ("POST".equalsIgnoreCase(method)) {
- mMethod = new HttpPost(url);
- mPostEntity = new StreamEntity();
- ((HttpPost)mMethod).setEntity(mPostEntity);
- } else if ("HEAD".equalsIgnoreCase(method)) {
- mMethod = new HttpHead(url);
- } else if ("PUT".equalsIgnoreCase(method)) {
- mMethod = new HttpPut(url);
- } else if ("DELETE".equalsIgnoreCase(method)) {
- mMethod = new HttpDelete(url);
- } else {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Method " + method + " not supported");
- }
- return false;
- }
- HttpParams params = mClient.getParams();
- // We handle the redirections C++-side
- HttpClientParams.setRedirecting(params, false);
- HttpProtocolParams.setUseExpectContinue(params, false);
- return true;
- }
-
- /**
- * We use this to start the connection thread (doing the method execute).
- * We usually always return true here, as the connection will run its
- * course in the thread.
- * We only return false if interrupted beforehand -- if a connection
- * problem happens, we will thus fail in either sendPostData() or
- * parseHeaders().
- */
- public synchronized boolean connectToRemote() {
- boolean ret = false;
- applyRequestHeaders();
- mConnectionFailedLock.lock();
- if (!mConnectionFailed) {
- mHttpThread = new Thread(new Connection());
- mHttpThread.start();
- }
- ret = mConnectionFailed;
- mConnectionFailedLock.unlock();
- return !ret;
- }
-
- /**
- * Get the complete response line of the HTTP request. Only valid on
- * completion of the transaction.
- * @return The complete HTTP response line, e.g "HTTP/1.0 200 OK".
- */
- public synchronized String getResponseLine() {
- return mResponseLine;
- }
-
- /**
- * Wait for the request thread completion
- * (unless already finished)
- */
- private void waitUntilConnectionFinished() {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "waitUntilConnectionFinished("
- + mConnectionFinished + ")");
- }
- if (!mConnectionFinished) {
- if (mHttpThread != null) {
- try {
- mHttpThread.join();
- mConnectionFinished = true;
- if (Config.LOGV) {
- Log.i(LOG_TAG, "http thread joined");
- }
- } catch (InterruptedException e) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "interrupted: " + e);
- }
- }
- } else {
- Log.e(LOG_TAG, ">>> Trying to join on mHttpThread " +
- "when it does not exist!");
- }
- }
- }
-
- // Headers handling
-
- /**
- * Receive all headers from the server and populate
- * mResponseHeaders.
- * @return True if headers are successfully received, False on
- * connection error.
- */
- public synchronized boolean parseHeaders() {
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- mConnectionFailedLock.unlock();
- return false;
- }
- mConnectionFailedLock.unlock();
- waitUntilConnectionFinished();
- mResponseHeaders = new HashMap<String, String[]>();
- if (mResponse == null)
- return false;
-
- Header[] headers = mResponse.getAllHeaders();
- for (int i = 0; i < headers.length; i++) {
- Header header = headers[i];
- if (Config.LOGV) {
- Log.i(LOG_TAG, "header " + header.getName()
- + " -> " + header.getValue());
- }
- setResponseHeader(header.getName(), header.getValue());
- }
-
- return true;
- }
-
- /**
- * Set a header to send with the HTTP request. Will not take effect
- * on a transaction already in progress. The key is associated
- * case-insensitive, but stored case-sensitive.
- * @param name The name of the header, e.g "Set-Cookie".
- * @param value The value for this header, e.g "text/html".
- */
- public synchronized void setRequestHeader(String name, String value) {
- String[] mapValue = { name, value };
- if (Config.LOGV) {
- Log.i(LOG_TAG, "setRequestHeader: " + name + " => " + value);
- }
- if (name.equalsIgnoreCase(KEY_CONTENT_LENGTH)) {
- setContentLength(Long.parseLong(value));
- } else {
- mRequestHeaders.put(name.toLowerCase(), mapValue);
- }
- }
-
- /**
- * Returns the value associated with the given request header.
- * @param name The name of the request header, non-null, case-insensitive.
- * @return The value associated with the request header, or null if
- * not set, or error.
- */
- public synchronized String getRequestHeader(String name) {
- String[] value = mRequestHeaders.get(name.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- }
-
- private void applyRequestHeaders() {
- if (mMethod == null)
- return;
- Iterator<String[]> it = mRequestHeaders.values().iterator();
- while (it.hasNext()) {
- // Set the key case-sensitive.
- String[] entry = it.next();
- if (Config.LOGV) {
- Log.i(LOG_TAG, "apply header " + entry[HEADERS_MAP_INDEX_KEY] +
- " => " + entry[HEADERS_MAP_INDEX_VALUE]);
- }
- mMethod.setHeader(entry[HEADERS_MAP_INDEX_KEY],
- entry[HEADERS_MAP_INDEX_VALUE]);
- }
- }
-
- /**
- * Returns the value associated with the given response header.
- * @param name The name of the response header, non-null, case-insensitive.
- * @return The value associated with the response header, or null if
- * not set or error.
- */
- public synchronized String getResponseHeader(String name) {
- if (mResponseHeaders != null) {
- String[] value = mResponseHeaders.get(name.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- } else {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "getResponseHeader() called but "
- + "response not received");
- }
- return null;
- }
- }
-
- /**
- * Return all response headers, separated by CR-LF line endings, and
- * ending with a trailing blank line. This mimics the format of the
- * raw response header up to but not including the body.
- * @return A string containing the entire response header.
- */
- public synchronized String getAllResponseHeaders() {
- if (mResponseHeaders == null) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "getAllResponseHeaders() called but "
- + "response not received");
- }
- return null;
- }
- StringBuilder result = new StringBuilder();
- Iterator<String[]> it = mResponseHeaders.values().iterator();
- while (it.hasNext()) {
- String[] entry = it.next();
- // Output the "key: value" lines.
- result.append(entry[HEADERS_MAP_INDEX_KEY]);
- result.append(": ");
- result.append(entry[HEADERS_MAP_INDEX_VALUE]);
- result.append(HTTP_LINE_ENDING);
- }
- result.append(HTTP_LINE_ENDING);
- return result.toString();
- }
-
-
- /**
- * Set a response header and associated value. The key is associated
- * case-insensitively, but stored case-sensitively.
- * @param name Case sensitive request header key.
- * @param value The associated value.
- */
- private void setResponseHeader(String name, String value) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Set response header " + name + ": " + value);
- }
- String mapValue[] = { name, value };
- mResponseHeaders.put(name.toLowerCase(), mapValue);
- }
-
- // Cookie handling
-
- /**
- * Get the cookie for the given URL.
- * @param url The fully qualified URL.
- * @return A string containing the cookie for the URL if it exists,
- * or null if not.
- */
- public static String getCookieForUrl(String url) {
- // Get the cookie for this URL, set as a header
- return CookieManager.getInstance().getCookie(url);
- }
-
- /**
- * Set the cookie for the given URL.
- * @param url The fully qualified URL.
- * @param cookie The new cookie value.
- * @return A string containing the cookie for the URL if it exists,
- * or null if not.
- */
- public static void setCookieForUrl(String url, String cookie) {
- // Get the cookie for this URL, set as a header
- CookieManager.getInstance().setCookie(url, cookie);
- }
-
- // Cache handling
-
- /**
- * Perform a request using LocalServer if possible. Initializes
- * class members so that receive() will obtain data from the stream
- * provided by the response.
- * @param url The fully qualified URL to try in LocalServer.
- * @return True if the url was found and is now setup to receive.
- * False if not found, with no side-effect.
- */
- public synchronized boolean useLocalServerResult(String url) {
- UrlInterceptHandlerGears handler =
- UrlInterceptHandlerGears.getInstance();
- if (handler == null) {
- return false;
- }
- UrlInterceptHandlerGears.ServiceResponse serviceResponse =
- handler.getServiceResponse(url, mRequestHeaders);
- if (serviceResponse == null) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "No response in LocalServer");
- }
- return false;
- }
- // LocalServer will handle this URL. Initialize stream and
- // response.
- mBodyInputStream = serviceResponse.getInputStream();
- mResponseLine = serviceResponse.getStatusLine();
- mResponseHeaders = serviceResponse.getResponseHeaders();
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Got response from LocalServer: " + mResponseLine);
- }
- return true;
- }
-
- /**
- * Perform a request using the cache result if present. Initializes
- * class members so that receive() will obtain data from the cache.
- * @param url The fully qualified URL to try in the cache.
- * @return True is the url was found and is now setup to receive
- * from cache. False if not found, with no side-effect.
- */
- public synchronized boolean useCacheResult(String url) {
- // Try the browser's cache. CacheManager wants a Map<String, String>.
- Map<String, String> cacheRequestHeaders = new HashMap<String, String>();
- Iterator<Map.Entry<String, String[]>> it =
- mRequestHeaders.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String[]> entry = it.next();
- cacheRequestHeaders.put(
- entry.getKey(),
- entry.getValue()[HEADERS_MAP_INDEX_VALUE]);
- }
- CacheResult mCacheResult =
- CacheManager.getCacheFile(url, cacheRequestHeaders);
- if (mCacheResult == null) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "No CacheResult for " + url);
- }
- return false;
- }
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Got CacheResult from browser cache");
- }
- // Check for expiry. -1 is "never", otherwise milliseconds since 1970.
- // Can be compared to System.currentTimeMillis().
- long expires = mCacheResult.getExpires();
- if (expires >= 0 && System.currentTimeMillis() >= expires) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "CacheResult expired "
- + (System.currentTimeMillis() - expires)
- + " milliseconds ago");
- }
- // Cache hit has expired. Do not return it.
- return false;
- }
- // Setup the mBodyInputStream to come from the cache.
- mBodyInputStream = mCacheResult.getInputStream();
- if (mBodyInputStream == null) {
- // Cache result may have gone away.
- if (Config.LOGV) {
- Log.i(LOG_TAG, "No mBodyInputStream for CacheResult " + url);
- }
- return false;
- }
- // Cache hit. Parse headers.
- synthesizeHeadersFromCacheResult(mCacheResult);
- return true;
- }
-
- /**
- * Take the limited set of headers in a CacheResult and synthesize
- * response headers.
- * @param cacheResult A CacheResult to populate mResponseHeaders with.
- */
- private void synthesizeHeadersFromCacheResult(CacheResult cacheResult) {
- int statusCode = cacheResult.getHttpStatusCode();
- // The status message is informal, so we can greatly simplify it.
- String statusMessage;
- if (statusCode >= 200 && statusCode < 300) {
- statusMessage = "OK";
- } else if (statusCode >= 300 && statusCode < 400) {
- statusMessage = "MOVED";
- } else {
- statusMessage = "UNAVAILABLE";
- }
- // Synthesize the response line.
- mResponseLine = "HTTP/1.1 " + statusCode + " " + statusMessage;
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Synthesized " + mResponseLine);
- }
- // Synthesize the returned headers from cache.
- mResponseHeaders = new HashMap<String, String[]>();
- String contentLength = Long.toString(cacheResult.getContentLength());
- setResponseHeader(KEY_CONTENT_LENGTH, contentLength);
- long expires = cacheResult.getExpires();
- if (expires >= 0) {
- // "Expires" header is valid and finite. Milliseconds since 1970
- // epoch, formatted as RFC-1123.
- String expiresString = DateUtils.formatDate(new Date(expires));
- setResponseHeader(KEY_EXPIRES, expiresString);
- }
- String lastModified = cacheResult.getLastModified();
- if (lastModified != null) {
- // Last modification time of the page. Passed end-to-end, but
- // not used by us.
- setResponseHeader(KEY_LAST_MODIFIED, lastModified);
- }
- String eTag = cacheResult.getETag();
- if (eTag != null) {
- // Entity tag. A kind of GUID to identify identical resources.
- setResponseHeader(KEY_ETAG, eTag);
- }
- String location = cacheResult.getLocation();
- if (location != null) {
- // If valid, refers to the location of a redirect.
- setResponseHeader(KEY_LOCATION, location);
- }
- String mimeType = cacheResult.getMimeType();
- if (mimeType == null) {
- // Use a safe default MIME type when none is
- // specified. "text/plain" is safe to render in the browser
- // window (even if large) and won't be intepreted as anything
- // that would cause execution.
- mimeType = DEFAULT_MIME_TYPE;
- }
- String encoding = cacheResult.getEncoding();
- // Encoding may not be specified. No default.
- String contentType = mimeType;
- if (encoding != null) {
- if (encoding.length() > 0) {
- contentType += "; charset=" + encoding;
- }
- }
- setResponseHeader(KEY_CONTENT_TYPE, contentType);
- }
-
- /**
- * Create a CacheResult for this URL. This enables the repsonse body
- * to be sent in calls to appendCacheResult().
- * @param url The fully qualified URL to add to the cache.
- * @param responseCode The response code returned for the request, e.g 200.
- * @param mimeType The MIME type of the body, e.g "text/plain".
- * @param encoding The encoding, e.g "utf-8". Use "" for unknown.
- */
- public synchronized boolean createCacheResult(
- String url, int responseCode, String mimeType, String encoding) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Making cache entry for " + url);
- }
- // Take the headers and parse them into a format needed by
- // CacheManager.
- Headers cacheHeaders = new Headers();
- Iterator<Map.Entry<String, String[]>> it =
- mResponseHeaders.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String[]> entry = it.next();
- // Headers.parseHeader() expects lowercase keys.
- String keyValue = entry.getKey() + ": "
- + entry.getValue()[HEADERS_MAP_INDEX_VALUE];
- CharArrayBuffer buffer = new CharArrayBuffer(keyValue.length());
- buffer.append(keyValue);
- // Parse it into the header container.
- cacheHeaders.parseHeader(buffer);
- }
- mCacheResult = CacheManager.createCacheFile(
- url, responseCode, cacheHeaders, mimeType, true);
- if (mCacheResult != null) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Saving into cache");
- }
- mCacheResult.setEncoding(encoding);
- mCacheResultUrl = url;
- return true;
- } else {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Couldn't create mCacheResult");
- }
- return false;
- }
- }
-
- /**
- * Add data from the response body to the CacheResult created with
- * createCacheResult().
- * @param data A byte array of the next sequential bytes in the
- * response body.
- * @param bytes The number of bytes to write from the start of
- * the array.
- * @return True if all bytes successfully written, false on failure.
- */
- public synchronized boolean appendCacheResult(byte[] data, int bytes) {
- if (mCacheResult == null) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "appendCacheResult() called without a "
- + "CacheResult initialized");
- }
- return false;
- }
- try {
- mCacheResult.getOutputStream().write(data, 0, bytes);
- } catch (IOException ex) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Got IOException writing cache data: " + ex);
- }
- return false;
- }
- return true;
- }
-
- /**
- * Save the completed CacheResult into the CacheManager. This must
- * have been created first with createCacheResult().
- * @return Returns true if the entry has been successfully saved.
- */
- public synchronized boolean saveCacheResult() {
- if (mCacheResult == null || mCacheResultUrl == null) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Tried to save cache result but "
- + "createCacheResult not called");
- }
- return false;
- }
-
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Saving cache result");
- }
- CacheManager.saveCacheFile(mCacheResultUrl, mCacheResult);
- mCacheResult = null;
- mCacheResultUrl = null;
- return true;
- }
-
-
- /**
- * Interrupt a blocking IO operation. This will cause the child
- * thread to expediently return from an operation if it was stuck at
- * the time. Note that this inherently races, and unfortunately
- * requires the caller to loop.
- */
- public synchronized void interrupt() {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "INTERRUPT CALLED");
- }
- mConnectionFailedLock.lock();
- mConnectionFailed = true;
- mConnectionFailedLock.unlock();
- if (mMethod != null) {
- mMethod.abort();
- }
- if (mHttpThread != null) {
- waitUntilConnectionFinished();
- }
- }
-
- /**
- * Receive the next sequential bytes of the response body after
- * successful connection. This will receive up to the size of the
- * provided byte array. If there is no body, this will return 0
- * bytes on the first call after connection.
- * @param buf A pre-allocated byte array to receive data into.
- * @return The number of bytes from the start of the array which
- * have been filled, 0 on EOF, or negative on error.
- */
- public synchronized int receive(byte[] buf) {
- if (mBodyInputStream == null) {
- // If this is the first call, setup the InputStream. This may
- // fail if there were headers, but no body returned by the
- // server.
- try {
- if (mResponse != null) {
- HttpEntity entity = mResponse.getEntity();
- mBodyInputStream = entity.getContent();
- }
- } catch (IOException inputException) {
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Failed to connect InputStream: "
- + inputException);
- }
- // Not unexpected. For example, 404 response return headers,
- // and sometimes a body with a detailed error.
- }
- if (mBodyInputStream == null) {
- // No error stream either. Treat as a 0 byte response.
- if (Config.LOGV) {
- Log.i(LOG_TAG, "No InputStream");
- }
- return 0; // EOF.
- }
- }
- int ret;
- try {
- int got = mBodyInputStream.read(buf);
- if (got > 0) {
- // Got some bytes, not EOF.
- ret = got;
- } else {
- // EOF.
- mBodyInputStream.close();
- ret = 0;
- }
- } catch (IOException e) {
- // An abort() interrupts us by calling close() on our stream.
- if (Config.LOGV) {
- Log.i(LOG_TAG, "Got IOException in mBodyInputStream.read(): ", e);
- }
- ret = -1;
- }
- return ret;
- }
-
- /**
- * For POST method requests, send a stream of data provided by the
- * native side in repeated callbacks.
- * We put the data in mBuffer, and wait until it is consumed
- * by the StreamEntity in the request thread.
- * @param data A byte array containing the data to sent, or null
- * if indicating EOF.
- * @param bytes The number of bytes from the start of the array to
- * send, or 0 if indicating EOF.
- * @return True if all bytes were successfully sent, false on error.
- */
- public boolean sendPostData(byte[] data, int bytes) {
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- mConnectionFailedLock.unlock();
- return false;
- }
- mConnectionFailedLock.unlock();
- if (mPostEntity == null) return false;
-
- // We block until the outputstream is available
- // (or in case of connection error)
- if (!mPostEntity.isReady()) return false;
-
- if (data == null && bytes == 0) {
- mBuffer.put(null);
- } else {
- mBuffer.put(new DataPacket(data, bytes));
- }
- mSignal.waitUntilPacketConsumed();
-
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- Log.e(LOG_TAG, "failure");
- mConnectionFailedLock.unlock();
- return false;
- }
- mConnectionFailedLock.unlock();
- return true;
- }
-
-}
diff --git a/core/java/android/webkit/gears/DesktopAndroid.java b/core/java/android/webkit/gears/DesktopAndroid.java
deleted file mode 100644
index ee8ca49..0000000
--- a/core/java/android/webkit/gears/DesktopAndroid.java
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.util.Log;
-import android.webkit.WebView;
-
-/**
- * Utility class to create a shortcut on Android
- */
-public class DesktopAndroid {
-
- private static final String TAG = "Gears-J-Desktop";
- private static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
- private static final String ACTION_INSTALL_SHORTCUT =
- "com.android.launcher.action.INSTALL_SHORTCUT";
-
- // Android now enforces a 64x64 limit for the icon
- private static int MAX_WIDTH = 64;
- private static int MAX_HEIGHT = 64;
-
- /**
- * Small utility function returning a Bitmap object.
- *
- * @param path the icon path
- */
- private static Bitmap getBitmap(String path) {
- return BitmapFactory.decodeFile(path);
- }
-
- /**
- * Create a shortcut for a webpage.
- *
- * <p>To set a shortcut on Android, we use the ACTION_INSTALL_SHORTCUT
- * from the default Home application. We only have to create an Intent
- * containing extra parameters specifying the shortcut.
- * <p>Note: the shortcut mechanism is not system wide and depends on the
- * Home application; if phone carriers decide to rewrite a Home application
- * that does not accept this Intent, no shortcut will be added.
- *
- * @param webview the webview we are called from
- * @param title the shortcut's title
- * @param url the shortcut's url
- * @param imagePath the local path of the shortcut's icon
- */
- public static void setShortcut(WebView webview, String title,
- String url, String imagePath) {
- Context context = webview.getContext();
-
- Intent viewWebPage = new Intent(Intent.ACTION_VIEW);
- viewWebPage.setData(Uri.parse(url));
- viewWebPage.addCategory(Intent.CATEGORY_BROWSABLE);
-
- Intent intent = new Intent(ACTION_INSTALL_SHORTCUT);
- intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, viewWebPage);
- intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
-
- // We disallow the creation of duplicate shortcuts (i.e. same
- // url, same title, but different screen position).
- intent.putExtra(EXTRA_SHORTCUT_DUPLICATE, false);
-
- Bitmap bmp = getBitmap(imagePath);
- if (bmp != null) {
- if ((bmp.getWidth() > MAX_WIDTH) ||
- (bmp.getHeight() > MAX_HEIGHT)) {
- Bitmap scaledBitmap = Bitmap.createScaledBitmap(bmp,
- MAX_WIDTH, MAX_HEIGHT, true);
- intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, scaledBitmap);
- } else {
- intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bmp);
- }
- } else {
- // This should not happen as we just downloaded the icon
- Log.e(TAG, "icon file <" + imagePath + "> not found");
- }
-
- context.sendBroadcast(intent);
- }
-
-}
diff --git a/core/java/android/webkit/gears/NativeDialog.java b/core/java/android/webkit/gears/NativeDialog.java
deleted file mode 100644
index 9e2b375..0000000
--- a/core/java/android/webkit/gears/NativeDialog.java
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import java.io.File;
-import java.lang.InterruptedException;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Utility class to call a modal native dialog on Android
- * The dialog itself is an Activity defined in the Browser.
- * @hide
- */
-public class NativeDialog {
-
- private static final String TAG = "Gears-J-NativeDialog";
-
- private final String DIALOG_PACKAGE = "com.android.browser";
- private final String DIALOG_CLASS = DIALOG_PACKAGE + ".GearsNativeDialog";
-
- private static Lock mLock = new ReentrantLock();
- private static Condition mDialogFinished = mLock.newCondition();
- private static String mResults = null;
-
- private static boolean mAsynchronousDialog;
-
- /**
- * Utility function to build the intent calling the
- * dialog activity
- */
- private Intent createIntent(String type, String arguments) {
- Intent intent = new Intent();
- intent.setClassName(DIALOG_PACKAGE, DIALOG_CLASS);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra("dialogArguments", arguments);
- intent.putExtra("dialogType", type);
- return intent;
- }
-
- /**
- * Opens a native dialog synchronously and waits for its completion.
- *
- * The dialog is an activity (GearsNativeDialog) provided by the Browser
- * that we call via startActivity(). Contrary to a normal activity though,
- * we need to block until it returns. To do so, we define a static lock
- * object in this class, which GearsNativeDialog can unlock once done
- */
- public String showDialog(Context context, String file,
- String arguments) {
-
- try {
- mAsynchronousDialog = false;
- mLock.lock();
- File path = new File(file);
- String fileName = path.getName();
- String type = fileName.substring(0, fileName.indexOf(".html"));
- Intent intent = createIntent(type, arguments);
-
- mResults = null;
- context.startActivity(intent);
- mDialogFinished.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "exception e: " + e);
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "exception e: " + e);
- } finally {
- mLock.unlock();
- }
-
- return mResults;
- }
-
- /**
- * Opens a native dialog asynchronously
- *
- * The dialog is an activity (GearsNativeDialog) provided by the
- * Browser.
- */
- public void showAsyncDialog(Context context, String type,
- String arguments) {
- mAsynchronousDialog = true;
- Intent intent = createIntent(type, arguments);
- context.startActivity(intent);
- }
-
- /**
- * Static method that GearsNativeDialog calls to unlock us
- */
- public static void signalFinishedDialog() {
- if (!mAsynchronousDialog) {
- mLock.lock();
- mDialogFinished.signal();
- mLock.unlock();
- } else {
- // we call the native callback
- closeAsynchronousDialog(mResults);
- }
- }
-
- /**
- * Static method that GearsNativeDialog calls to set the
- * dialog's result
- */
- public static void closeDialog(String res) {
- mResults = res;
- }
-
- /**
- * Native callback method
- */
- private native static void closeAsynchronousDialog(String res);
-}
diff --git a/core/java/android/webkit/gears/PluginSettings.java b/core/java/android/webkit/gears/PluginSettings.java
deleted file mode 100644
index 2d0cc13..0000000
--- a/core/java/android/webkit/gears/PluginSettings.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.util.Log;
-import android.webkit.Plugin;
-import android.webkit.Plugin.PreferencesClickHandler;
-
-/**
- * Simple bridge class intercepting the click in the
- * browser plugin list and calling the Gears settings
- * dialog.
- */
-public class PluginSettings {
-
- private static final String TAG = "Gears-J-PluginSettings";
- private Context mContext;
-
- public PluginSettings(Plugin plugin) {
- plugin.setClickHandler(new ClickHandler());
- }
-
- /**
- * We do not call the dialog synchronously here as the main
- * message loop would be blocked, so we call it via a secondary thread.
- */
- private class ClickHandler implements PreferencesClickHandler {
- public void handleClickEvent(Context context) {
- mContext = context.getApplicationContext();
- Thread startDialog = new Thread(new StartDialog(context));
- startDialog.start();
- }
- }
-
- /**
- * Simple wrapper class to call the gears native method in
- * a separate thread (the native code will then instanciate a NativeDialog
- * object which will start the GearsNativeDialog activity defined in
- * the Browser).
- */
- private class StartDialog implements Runnable {
- Context mContext;
-
- public StartDialog(Context context) {
- mContext = context;
- }
-
- public void run() {
- runSettingsDialog(mContext);
- }
- }
-
- private static native void runSettingsDialog(Context c);
-
-}
diff --git a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
deleted file mode 100644
index 2a5cbe9..0000000
--- a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
+++ /dev/null
@@ -1,501 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.net.http.Headers;
-import android.util.Log;
-import android.webkit.CacheManager;
-import android.webkit.CacheManager.CacheResult;
-import android.webkit.Plugin;
-import android.webkit.UrlInterceptRegistry;
-import android.webkit.UrlInterceptHandler;
-import android.webkit.WebView;
-
-import org.apache.http.impl.cookie.DateUtils;
-import org.apache.http.util.CharArrayBuffer;
-
-import java.io.*;
-import java.util.*;
-
-/**
- * Services requests to handle URLs coming from the browser or
- * HttpRequestAndroid. This registers itself with the
- * UrlInterceptRegister in Android so we get a chance to service all
- * URLs passing through the browser before anything else.
- */
-public class UrlInterceptHandlerGears implements UrlInterceptHandler {
- /** Singleton instance. */
- private static UrlInterceptHandlerGears instance;
- /** Debug logging tag. */
- private static final String LOG_TAG = "Gears-J";
- /** Buffer size for reading/writing streams. */
- private static final int BUFFER_SIZE = 4096;
- /**
- * Number of milliseconds to expire LocalServer temporary entries in
- * the browser's cache. Somewhat arbitrarily chosen as a compromise
- * between being a) long enough not to expire during page load and
- * b) short enough to evict entries during a session. */
- private static final int CACHE_EXPIRY_MS = 60000; // 1 minute.
- /** Enable/disable all logging in this class. */
- private static boolean logEnabled = false;
- /** The unmodified (case-sensitive) key in the headers map is the
- * same index as used by HttpRequestAndroid. */
- public static final int HEADERS_MAP_INDEX_KEY =
- ApacheHttpRequestAndroid.HEADERS_MAP_INDEX_KEY;
- /** The associated value in the headers map is the same index as
- * used by HttpRequestAndroid. */
- public static final int HEADERS_MAP_INDEX_VALUE =
- ApacheHttpRequestAndroid.HEADERS_MAP_INDEX_VALUE;
-
- /**
- * Object passed to the native side, containing information about
- * the URL to service.
- */
- public static class ServiceRequest {
- // The URL being requested.
- private String url;
- // Request headers. Map of lowercase key to [ unmodified key, value ].
- private Map<String, String[]> requestHeaders;
-
- /**
- * Initialize members on construction.
- * @param url The URL being requested.
- * @param requestHeaders Headers associated with the request,
- * or null if none.
- * Map of lowercase key to [ unmodified key, value ].
- */
- public ServiceRequest(String url, Map<String, String[]> requestHeaders) {
- this.url = url;
- this.requestHeaders = requestHeaders;
- }
-
- /**
- * Returns the URL being requested.
- * @return The URL being requested.
- */
- public String getUrl() {
- return url;
- }
-
- /**
- * Get the value associated with a request header key, if any.
- * @param header The key to find, case insensitive.
- * @return The value associated with this header, or null if not found.
- */
- public String getRequestHeader(String header) {
- if (requestHeaders != null) {
- String[] value = requestHeaders.get(header.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- } else {
- return null;
- }
- }
- }
-
- /**
- * Object returned by the native side, containing information needed
- * to pass the entire response back to the browser or
- * HttpRequestAndroid. Works from either an in-memory array or a
- * file on disk.
- */
- public class ServiceResponse {
- // The response status code, e.g 200.
- private int statusCode;
- // The full status line, e.g "HTTP/1.1 200 OK".
- private String statusLine;
- // All headers associated with the response. Map of lowercase key
- // to [ unmodified key, value ].
- private Map<String, String[]> responseHeaders =
- new HashMap<String, String[]>();
- // The MIME type, e.g "text/html".
- private String mimeType;
- // The encoding, e.g "utf-8", or null if none.
- private String encoding;
- // The stream which contains the body when read().
- private InputStream inputStream;
-
- /**
- * Initialize members using an in-memory array to return the body.
- * @param statusCode The response status code, e.g 200.
- * @param statusLine The full status line, e.g "HTTP/1.1 200 OK".
- * @param mimeType The MIME type, e.g "text/html".
- * @param encoding Encoding, e.g "utf-8" or null if none.
- * @param body The response body as a byte array, non-empty.
- */
- void setResultArray(
- int statusCode,
- String statusLine,
- String mimeType,
- String encoding,
- byte[] body) {
- this.statusCode = statusCode;
- this.statusLine = statusLine;
- this.mimeType = mimeType;
- this.encoding = encoding;
- // Setup a stream to read out of the byte array.
- this.inputStream = new ByteArrayInputStream(body);
- }
-
- /**
- * Initialize members using a file on disk to return the body.
- * @param statusCode The response status code, e.g 200.
- * @param statusLine The full status line, e.g "HTTP/1.1 200 OK".
- * @param mimeType The MIME type, e.g "text/html".
- * @param encoding Encoding, e.g "utf-8" or null if none.
- * @param path Full path to the file containing the body.
- * @return True if the file is successfully setup to stream,
- * false on error such as file not found.
- */
- boolean setResultFile(
- int statusCode,
- String statusLine,
- String mimeType,
- String encoding,
- String path) {
- this.statusCode = statusCode;
- this.statusLine = statusLine;
- this.mimeType = mimeType;
- this.encoding = encoding;
- try {
- // Setup a stream to read out of a file on disk.
- this.inputStream = new FileInputStream(new File(path));
- return true;
- } catch (java.io.FileNotFoundException ex) {
- log("File not found: " + path);
- return false;
- }
- }
-
- /**
- * Set a response header, adding its settings to the header members.
- * @param key The case sensitive key for the response header,
- * e.g "Set-Cookie".
- * @param value The value associated with this key, e.g "cookie1234".
- */
- public void setResponseHeader(String key, String value) {
- // The map value contains the unmodified key (not lowercase).
- String[] mapValue = { key, value };
- responseHeaders.put(key.toLowerCase(), mapValue);
- }
-
- /**
- * Return the "Content-Type" header possibly supplied by a
- * previous setResponseHeader().
- * @return The "Content-Type" value, or null if not present.
- */
- public String getContentType() {
- // The map keys are lowercase.
- String[] value = responseHeaders.get("content-type");
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- }
-
- /**
- * Returns the HTTP status code for the response, supplied in
- * setResultArray() or setResultFile().
- * @return The HTTP statue code, e.g 200.
- */
- public int getStatusCode() {
- return statusCode;
- }
-
- /**
- * Returns the full HTTP status line for the response, supplied in
- * setResultArray() or setResultFile().
- * @return The HTTP statue line, e.g "HTTP/1.1 200 OK".
- */
- public String getStatusLine() {
- return statusLine;
- }
-
- /**
- * Get all response headers supplied in calls in
- * setResponseHeader().
- * @return A Map<String, String[]> containing all headers.
- */
- public Map<String, String[]> getResponseHeaders() {
- return responseHeaders;
- }
-
- /**
- * Returns the MIME type for the response, supplied in
- * setResultArray() or setResultFile().
- * @return The MIME type, e.g "text/html".
- */
- public String getMimeType() {
- return mimeType;
- }
-
- /**
- * Returns the encoding for the response, supplied in
- * setResultArray() or setResultFile(), or null if none.
- * @return The encoding, e.g "utf-8", or null if none.
- */
- public String getEncoding() {
- return encoding;
- }
-
- /**
- * Returns the InputStream setup by setResultArray() or
- * setResultFile() to allow reading data either from memory or
- * disk.
- * @return The InputStream containing the response body.
- */
- public InputStream getInputStream() {
- return inputStream;
- }
- }
-
- /**
- * Construct and initialize the singleton instance.
- */
- public UrlInterceptHandlerGears() {
- if (instance != null) {
- Log.e(LOG_TAG, "UrlInterceptHandlerGears singleton already constructed");
- throw new RuntimeException();
- }
- instance = this;
- }
-
- /**
- * Turn on/off logging in this class.
- * @param on Logging enable state.
- */
- public static void enableLogging(boolean on) {
- logEnabled = on;
- }
-
- /**
- * Get the singleton instance.
- * @return The singleton instance.
- */
- public static UrlInterceptHandlerGears getInstance() {
- return instance;
- }
-
- /**
- * Register the singleton instance with the browser's interception
- * mechanism.
- */
- public synchronized void register() {
- UrlInterceptRegistry.registerHandler(this);
- }
-
- /**
- * Unregister the singleton instance from the browser's interception
- * mechanism.
- */
- public synchronized void unregister() {
- UrlInterceptRegistry.unregisterHandler(this);
- }
-
- /**
- * Copy the entire InputStream to OutputStream.
- * @param inputStream The stream to read from.
- * @param outputStream The stream to write to.
- * @return True if the entire stream copied successfully, false on error.
- */
- private boolean copyStream(InputStream inputStream,
- OutputStream outputStream) {
- try {
- // Temporary buffer to copy stream through.
- byte[] buf = new byte[BUFFER_SIZE];
- for (;;) {
- // Read up to BUFFER_SIZE bytes.
- int bytes = inputStream.read(buf);
- if (bytes < 0) {
- break;
- }
- // Write the number of bytes we just read.
- outputStream.write(buf, 0, bytes);
- }
- } catch (IOException ex) {
- log("Got IOException copying stream: " + ex);
- return false;
- }
- return true;
- }
-
- /**
- * Given an URL, returns a CacheResult which contains the response
- * for the request. This implements the UrlInterceptHandler interface.
- *
- * @param url The fully qualified URL being requested.
- * @param requestHeaders The request headers for this URL.
- * @return If a response can be crafted, a CacheResult initialized
- * to return the surrogate response. If this URL cannot
- * be serviced, returns null.
- */
- public CacheResult service(String url, Map<String, String> requestHeaders) {
- // Thankfully the browser does call us with case-sensitive
- // headers. We just need to map it case-insensitive.
- Map<String, String[]> lowercaseRequestHeaders =
- new HashMap<String, String[]>();
- Iterator<Map.Entry<String, String>> requestHeadersIt =
- requestHeaders.entrySet().iterator();
- while (requestHeadersIt.hasNext()) {
- Map.Entry<String, String> entry = requestHeadersIt.next();
- String key = entry.getKey();
- String mapValue[] = { key, entry.getValue() };
- lowercaseRequestHeaders.put(key.toLowerCase(), mapValue);
- }
- ServiceResponse response = getServiceResponse(url, lowercaseRequestHeaders);
- if (response == null) {
- // No result for this URL.
- return null;
- }
- // Translate the ServiceResponse to a CacheResult.
- // Translate http -> gears, https -> gearss, so we don't overwrite
- // existing entries.
- String gearsUrl = "gears" + url.substring("http".length());
- // Set the result to expire, so that entries don't pollute the
- // browser's cache for too long.
- long now_ms = System.currentTimeMillis();
- String expires = DateUtils.formatDate(new Date(now_ms + CACHE_EXPIRY_MS));
- response.setResponseHeader(ApacheHttpRequestAndroid.KEY_EXPIRES, expires);
- // The browser is only interested in a small subset of headers,
- // contained in a Headers object. Iterate the map of all headers
- // and add them to Headers.
- Headers headers = new Headers();
- Iterator<Map.Entry<String, String[]>> responseHeadersIt =
- response.getResponseHeaders().entrySet().iterator();
- while (responseHeadersIt.hasNext()) {
- Map.Entry<String, String[]> entry = responseHeadersIt.next();
- // Headers.parseHeader() expects lowercase keys.
- String keyValue = entry.getKey() + ": "
- + entry.getValue()[HEADERS_MAP_INDEX_VALUE];
- CharArrayBuffer buffer = new CharArrayBuffer(keyValue.length());
- buffer.append(keyValue);
- // Parse it into the header container.
- headers.parseHeader(buffer);
- }
- CacheResult cacheResult = CacheManager.createCacheFile(
- gearsUrl,
- response.getStatusCode(),
- headers,
- response.getMimeType(),
- true); // forceCache
-
- if (cacheResult == null) {
- // With the no-cache policy we could end up
- // with a null result
- return null;
- }
-
- // Set encoding if specified.
- String encoding = response.getEncoding();
- if (encoding != null) {
- cacheResult.setEncoding(encoding);
- }
- // Copy the response body to the CacheResult. This handles all
- // combinations of memory vs on-disk on both sides.
- InputStream inputStream = response.getInputStream();
- OutputStream outputStream = cacheResult.getOutputStream();
- boolean copied = copyStream(inputStream, outputStream);
- // Close the input and output streams to relinquish their
- // resources earlier.
- try {
- inputStream.close();
- } catch (IOException ex) {
- log("IOException closing InputStream: " + ex);
- copied = false;
- }
- try {
- outputStream.close();
- } catch (IOException ex) {
- log("IOException closing OutputStream: " + ex);
- copied = false;
- }
- if (!copied) {
- log("copyStream of local result failed");
- return null;
- }
- // Save the entry into the browser's cache.
- CacheManager.saveCacheFile(gearsUrl, cacheResult);
- // Get it back from the cache, this time properly initialized to
- // be used for input.
- cacheResult = CacheManager.getCacheFile(gearsUrl, null);
- if (cacheResult != null) {
- log("Returning surrogate result");
- return cacheResult;
- } else {
- // Not an expected condition, but handle gracefully. Perhaps out
- // of memory or disk?
- Log.e(LOG_TAG, "Lost CacheResult between save and get. Can't serve.\n");
- return null;
- }
- }
-
- /**
- * Given an URL, returns a CacheResult and headers which contain the
- * response for the request.
- *
- * @param url The fully qualified URL being requested.
- * @param requestHeaders The request headers for this URL.
- * @return If a response can be crafted, a ServiceResponse is
- * created which contains all response headers and an InputStream
- * attached to the body. If there is no response, null is returned.
- */
- public ServiceResponse getServiceResponse(String url,
- Map<String, String[]> requestHeaders) {
- if (!url.startsWith("http://") && !url.startsWith("https://")) {
- // Don't know how to service non-HTTP URLs
- return null;
- }
- // Call the native handler to craft a response for this URL.
- return nativeService(new ServiceRequest(url, requestHeaders));
- }
-
- /**
- * Convenience debug function. Calls the Android logging
- * mechanism. logEnabled is not a constant, so if the string
- * evaluation is potentially expensive, the caller also needs to
- * check it.
- * @param str String to log to the Android console.
- */
- private void log(String str) {
- if (logEnabled) {
- Log.i(LOG_TAG, str);
- }
- }
-
- /**
- * Native method which handles the bulk of the request in LocalServer.
- * @param request A ServiceRequest object containing information about
- * the request.
- * @return If serviced, a ServiceResponse object containing all the
- * information to provide a response for the URL, or null
- * if no response available for this URL.
- */
- private native static ServiceResponse nativeService(ServiceRequest request);
-}
diff --git a/core/java/android/webkit/gears/VersionExtractor.java b/core/java/android/webkit/gears/VersionExtractor.java
deleted file mode 100644
index 172dacb..0000000
--- a/core/java/android/webkit/gears/VersionExtractor.java
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.util.Log;
-import java.io.IOException;
-import java.io.StringReader;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.FactoryConfigurationError;
-import javax.xml.parsers.ParserConfigurationException;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.w3c.dom.Document;
-import org.w3c.dom.DOMException;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-/**
- * A class that can extract the Gears version and upgrade URL from an
- * xml document.
- */
-public final class VersionExtractor {
-
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-VersionExtractor";
- /**
- * XML element names.
- */
- private static final String VERSION = "em:version";
- private static final String URL = "em:updateLink";
-
- /**
- * Parses the input xml string and invokes the native
- * setVersionAndUrl method.
- * @param xml is the XML string to parse.
- * @return true if the extraction is successful and false otherwise.
- */
- public static boolean extract(String xml, long nativeObject) {
- try {
- // Build the builders.
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
-
- // Create the document.
- Document doc = builder.parse(new InputSource(new StringReader(xml)));
-
- // Look for the version and url elements and get their text
- // contents.
- String version = extractText(doc, VERSION);
- String url = extractText(doc, URL);
-
- // If we have both, let the native side know.
- if (version != null && url != null) {
- setVersionAndUrl(version, url, nativeObject);
- return true;
- }
-
- return false;
-
- } catch (FactoryConfigurationError ex) {
- Log.e(TAG, "Could not create the DocumentBuilderFactory " + ex);
- } catch (ParserConfigurationException ex) {
- Log.e(TAG, "Could not create the DocumentBuilder " + ex);
- } catch (SAXException ex) {
- Log.e(TAG, "Could not parse the xml " + ex);
- } catch (IOException ex) {
- Log.e(TAG, "Could not read the xml " + ex);
- }
-
- return false;
- }
-
- /**
- * Extracts the text content of the first element with the given name.
- * @param doc is the Document where the element is searched for.
- * @param elementName is name of the element to searched for.
- * @return the text content of the element or null if no such
- * element is found.
- */
- private static String extractText(Document doc, String elementName) {
- String text = null;
- NodeList node_list = doc.getElementsByTagName(elementName);
-
- if (node_list.getLength() > 0) {
- // We are only interested in the first node. Normally there
- // should not be more than one anyway.
- Node node = node_list.item(0);
-
- // Iterate through the text children.
- NodeList child_list = node.getChildNodes();
-
- try {
- for (int i = 0; i < child_list.getLength(); ++i) {
- Node child = child_list.item(i);
- if (child.getNodeType() == Node.TEXT_NODE) {
- if (text == null) {
- text = new String();
- }
- text += child.getNodeValue();
- }
- }
- } catch (DOMException ex) {
- Log.e(TAG, "getNodeValue() failed " + ex);
- }
- }
-
- if (text != null) {
- text = text.trim();
- }
-
- return text;
- }
-
- /**
- * Native method used to send the version and url back to the C++
- * side.
- */
- private static native void setVersionAndUrl(
- String version, String url, long nativeObject);
-}
diff --git a/core/java/android/webkit/gears/ZipInflater.java b/core/java/android/webkit/gears/ZipInflater.java
deleted file mode 100644
index f6b6be5..0000000
--- a/core/java/android/webkit/gears/ZipInflater.java
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.os.StatFs;
-import android.util.Log;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.zip.CRC32;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
-
-
-/**
- * A class that can inflate a zip archive.
- */
-public final class ZipInflater {
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-ZipInflater";
-
- /**
- * The size of the buffer used to read from the archive.
- */
- private static final int BUFFER_SIZE_BYTES = 32 * 1024; // 32 KB.
- /**
- * The path navigation component (i.e. "../").
- */
- private static final String PATH_NAVIGATION_COMPONENT = ".." + File.separator;
- /**
- * The root of the data partition.
- */
- private static final String DATA_PARTITION_ROOT = "/data";
-
- /**
- * We need two be able to store two versions of gears in parallel:
- * - the zipped version
- * - the unzipped version, which will be loaded next time the browser is started.
- * We are conservative and do not attempt to unpack unless there enough free
- * space on the device to store 4 times the new Gears size.
- */
- private static final long SIZE_MULTIPLIER = 4;
-
- /**
- * Unzips the archive with the given name.
- * @param filename is the name of the zip to inflate.
- * @param path is the path where the zip should be unpacked. It must contain
- * a trailing separator, or the extraction will fail.
- * @return true if the extraction is successful and false otherwise.
- */
- public static boolean inflate(String filename, String path) {
- Log.i(TAG, "Extracting " + filename + " to " + path);
-
- // Check that the path ends with a separator.
- if (!path.endsWith(File.separator)) {
- Log.e(TAG, "Path missing trailing separator: " + path);
- return false;
- }
-
- boolean result = false;
-
- // Use a ZipFile to get an enumeration of the entries and
- // calculate the overall uncompressed size of the archive. Also
- // check for existing files or directories that have the same
- // name as the entries in the archive. Also check for invalid
- // entry names (e.g names that attempt to navigate to the
- // parent directory).
- ZipInputStream zipStream = null;
- long uncompressedSize = 0;
- try {
- ZipFile zipFile = new ZipFile(filename);
- try {
- Enumeration entries = zipFile.entries();
- while (entries.hasMoreElements()) {
- ZipEntry entry = (ZipEntry) entries.nextElement();
- uncompressedSize += entry.getSize();
- // Check against entry names that may attempt to navigate
- // out of the destination directory.
- if (entry.getName().indexOf(PATH_NAVIGATION_COMPONENT) >= 0) {
- throw new IOException("Illegal entry name: " + entry.getName());
- }
-
- // Check against entries with the same name as pre-existing files or
- // directories.
- File file = new File(path + entry.getName());
- if (file.exists()) {
- // A file or directory with the same name already exist.
- // This must not happen, so we treat this as an error.
- throw new IOException(
- "A file or directory with the same name already exists.");
- }
- }
- } finally {
- zipFile.close();
- }
-
- Log.i(TAG, "Determined uncompressed size: " + uncompressedSize);
- // Check we have enough space to unpack this archive.
- if (freeSpace() <= uncompressedSize * SIZE_MULTIPLIER) {
- throw new IOException("Not enough space to unpack this archive.");
- }
-
- zipStream = new ZipInputStream(
- new BufferedInputStream(new FileInputStream(filename)));
- ZipEntry entry;
- int counter;
- byte buffer[] = new byte[BUFFER_SIZE_BYTES];
-
- // Iterate through the entries and write each of them to a file.
- while ((entry = zipStream.getNextEntry()) != null) {
- File file = new File(path + entry.getName());
- if (entry.isDirectory()) {
- // If the entry denotes a directory, we need to create a
- // directory with the same name.
- file.mkdirs();
- } else {
- CRC32 checksum = new CRC32();
- BufferedOutputStream output = new BufferedOutputStream(
- new FileOutputStream(file),
- BUFFER_SIZE_BYTES);
- try {
- // Read the entry and write it to the file.
- while ((counter = zipStream.read(buffer, 0, BUFFER_SIZE_BYTES)) !=
- -1) {
- output.write(buffer, 0, counter);
- checksum.update(buffer, 0, counter);
- }
- output.flush();
- } finally {
- output.close();
- }
-
- if (checksum.getValue() != entry.getCrc()) {
- throw new IOException(
- "Integrity check failed for: " + entry.getName());
- }
- }
- zipStream.closeEntry();
- }
-
- result = true;
-
- } catch (FileNotFoundException ex) {
- Log.e(TAG, "The zip file could not be found. " + ex);
- } catch (IOException ex) {
- Log.e(TAG, "Could not read or write an entry. " + ex);
- } catch(IllegalArgumentException ex) {
- Log.e(TAG, "Could not create the BufferedOutputStream. " + ex);
- } finally {
- if (zipStream != null) {
- try {
- zipStream.close();
- } catch (IOException ex) {
- // Ignored.
- }
- }
- // Discard any exceptions and return the result to the native side.
- return result;
- }
- }
-
- private static final long freeSpace() {
- StatFs data_partition = new StatFs(DATA_PARTITION_ROOT);
- long freeSpace = data_partition.getAvailableBlocks() *
- data_partition.getBlockSize();
- Log.i(TAG, "Free space on the data partition: " + freeSpace);
- return freeSpace;
- }
-}
diff --git a/core/java/android/webkit/gears/package.html b/core/java/android/webkit/gears/package.html
deleted file mode 100644
index db6f78b..0000000
--- a/core/java/android/webkit/gears/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<body>
-{@hide}
-</body> \ No newline at end of file
diff --git a/core/java/android/webkit/package.html b/core/java/android/webkit/package.html
deleted file mode 100644
index 4ed08da..0000000
--- a/core/java/android/webkit/package.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<body>
-Provides tools for browsing the web.
-<p>The only classes or interfaces in this package intended for use by SDK
-developers are WebView, BroswerCallbackAdapter, BrowserCallback, and CookieManager.
-</body>
-</html> \ No newline at end of file