| /* |
| * 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.ActivityManager; |
| import android.content.Context; |
| import android.content.res.AssetManager; |
| import android.database.Cursor; |
| import android.graphics.Bitmap; |
| import android.net.ParseException; |
| import android.net.Uri; |
| import android.net.WebAddress; |
| import android.net.http.SslCertificate; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.provider.OpenableColumns; |
| import android.util.Log; |
| import android.util.TypedValue; |
| import android.view.Surface; |
| import android.view.WindowOrientationListener; |
| |
| import junit.framework.Assert; |
| |
| import java.io.InputStream; |
| import java.net.URLEncoder; |
| import java.util.HashMap; |
| import java.util.Map; |
| 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 Map<String, Object> mJSInterfaceMap; |
| |
| // Orientation listener |
| private WindowOrientationListener mOrientationListener; |
| |
| // message ids |
| // a message posted when a frame loading is completed |
| static final int FRAME_COMPLETED = 1001; |
| // orientation change message |
| static final int ORIENTATION_CHANGED = 1002; |
| // 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, Map<String, Object> javascriptInterfaces) { |
| |
| Context appContext = context.getApplicationContext(); |
| |
| // Create a global JWebCoreJavaBridge to handle timers and |
| // cookies in the WebCore thread. |
| if (sJavaBridge == null) { |
| sJavaBridge = new JWebCoreJavaBridge(appContext); |
| // set WebCore native cache size |
| ActivityManager am = (ActivityManager) context |
| .getSystemService(Context.ACTIVITY_SERVICE); |
| if (am.getMemoryClass() > 16) { |
| sJavaBridge.setCacheSize(8 * 1024 * 1024); |
| } else { |
| sJavaBridge.setCacheSize(4 * 1024 * 1024); |
| } |
| // initialize CacheManager |
| CacheManager.init(appContext); |
| // create CookieSyncManager with current Context |
| CookieSyncManager.createInstance(appContext); |
| // create PluginManager with current Context |
| PluginManager.getInstance(appContext); |
| } |
| mJSInterfaceMap = javascriptInterfaces; |
| |
| mSettings = settings; |
| mContext = context; |
| mCallbackProxy = proxy; |
| mDatabase = WebViewDatabase.getInstance(appContext); |
| mWebViewCore = w; |
| |
| AssetManager am = context.getAssets(); |
| nativeCreateFrame(w, am, proxy.getBackForwardList()); |
| |
| if (DebugFlags.BROWSER_FRAME) { |
| Log.v(LOGTAG, "BrowserFrame constructor: this=" + this); |
| } |
| |
| mOrientationListener = new WindowOrientationListener(context) { |
| @Override |
| public void onOrientationChanged(int orientation) { |
| switch (orientation) { |
| case Surface.ROTATION_90: |
| orientation = 90; |
| break; |
| case Surface.ROTATION_180: |
| orientation = 180; |
| break; |
| case Surface.ROTATION_270: |
| orientation = -90; |
| break; |
| case Surface.ROTATION_0: |
| orientation = 0; |
| break; |
| default: |
| break; |
| } |
| sendMessage( |
| obtainMessage(ORIENTATION_CHANGED, orientation, 0)); |
| } |
| }; |
| mOrientationListener.enable(); |
| } |
| |
| /** |
| * 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 a url with "POST" method from the network into the main frame. |
| * @param url The url to load. |
| * @param data The data for POST request. |
| */ |
| public void postUrl(String url, byte[] data) { |
| mLoadInitFromJava = true; |
| nativePostUrl(url, data); |
| 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. |
| resetLoadingStates(); |
| mCallbackProxy.onReceivedError(errorCode, description, failingUrl); |
| } |
| |
| private void resetLoadingStates() { |
| mCommitted = true; |
| mFirstLayoutDone = true; |
| } |
| |
| /* 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(); |
| } |
| } |
| |
| /** |
| * 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; |
| mWebViewCore.getWebView().mViewManager.postResetStateAll(); |
| } |
| } |
| |
| /** |
| * 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) { |
| resetLoadingStates(); |
| 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() { |
| mOrientationListener.disable(); |
| 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()) { |
| WebHistoryItem item = mCallbackProxy.getBackForwardList() |
| .getCurrentItem(); |
| if (item != null) { |
| WebAddress uri = new WebAddress(item.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; |
| } |
| |
| case ORIENTATION_CHANGED: { |
| nativeOrientationChanged(msg.arg1); |
| 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); |
| } |
| |
| /** |
| * Called by JNI. Given a URI, find the associated file and return its size |
| * @param uri A String representing the URI of the desired file. |
| * @return int The size of the given file. |
| */ |
| private int getFileSize(String uri) { |
| int size = 0; |
| Cursor cursor = mContext.getContentResolver().query(Uri.parse(uri), |
| new String[] { OpenableColumns.SIZE }, |
| null, |
| null, |
| null); |
| if (cursor != null) { |
| try { |
| if (cursor.moveToNext()) { |
| size = cursor.getInt(0); |
| } |
| } finally { |
| cursor.close(); |
| } |
| } |
| return size; |
| } |
| |
| /** |
| * Called by JNI. Given a URI, a buffer, and an offset into the buffer, |
| * copy the resource into buffer. |
| * @param uri A String representing the URI of the desired file. |
| * @param buffer The byte array to copy the data into. |
| * @param offset The offet into buffer to place the data. |
| * @param expectedSize The size that the buffer has allocated for this file. |
| * @return int The size of the given file, or zero if it fails. |
| */ |
| private int getFile(String uri, byte[] buffer, int offset, |
| int expectedSize) { |
| int size = 0; |
| try { |
| InputStream stream = mContext.getContentResolver() |
| .openInputStream(Uri.parse(uri)); |
| size = stream.available(); |
| if (size <= expectedSize && buffer != null |
| && buffer.length - offset >= size) { |
| stream.read(buffer, offset, size); |
| } else { |
| size = 0; |
| } |
| stream.close(); |
| } catch (java.io.FileNotFoundException e) { |
| Log.e(LOGTAG, "FileNotFoundException:" + e); |
| size = 0; |
| } catch (java.io.IOException e2) { |
| Log.e(LOGTAG, "IOException: " + e2); |
| size = 0; |
| } |
| return size; |
| } |
| |
| /** |
| * 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 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, |
| long postDataIdentifier, |
| int cacheMode, |
| boolean mainResource, |
| boolean userGesture, |
| 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 (DebugFlags.BROWSER_FRAME) { |
| 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 (DebugFlags.BROWSER_FRAME) { |
| Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method=" |
| + method + ", postData=" + postData + ", isMainFramePage=" |
| + isMainFramePage + ", mainResource=" + mainResource |
| + ", userGesture=" + userGesture); |
| } |
| |
| // Create a LoadListener |
| LoadListener loadListener = LoadListener.getLoadListener(mContext, |
| this, url, loaderHandle, synchronous, isMainFramePage, |
| mainResource, userGesture, postDataIdentifier); |
| |
| mCallbackProxy.onLoadResource(url); |
| |
| if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) { |
| // send an error message, so that loadListener can be deleted |
| // after this is returned. This is important as LoadListener's |
| // nativeError will remove the request from its DocLoader's request |
| // list. But the set up is not done until this method is returned. |
| loadListener.error( |
| android.net.http.EventHandler.ERROR, mContext.getString( |
| com.android.internal.R.string.httpErrorTooManyRequests)); |
| return loadListener; |
| } |
| |
| FrameLoader loader = new FrameLoader(loadListener, mSettings, method); |
| loader.setHeaders(headers); |
| loader.setPostData(postData); |
| // Set the load mode to the mode used for the current page. |
| // If WebKit wants validation, go to network directly. |
| loader.setCacheMode(headers.containsKey("If-Modified-Since") |
| || headers.containsKey("If-None-Match") ? |
| WebSettings.LOAD_NO_CACHE : cacheMode); |
| // Set referrer to current URL? |
| if (!loader.executeLoad()) { |
| checker.responseAlert("startLoadingResource fail"); |
| } |
| checker.responseAlert("startLoadingResource succeed"); |
| |
| 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); |
| } |
| |
| // Called by JNI when an apple-touch-icon attribute was found. |
| private void didReceiveTouchIconUrl(String url, boolean precomposed) { |
| mCallbackProxy.onReceivedTouchIconUrl(url, precomposed); |
| } |
| |
| /** |
| * 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 rawResId in PlatformBridge.h |
| private static final int NODOMAIN = 1; |
| private static final int LOADERROR = 2; |
| private static final int DRAWABLEDIR = 3; |
| private static final int FILE_UPLOAD_LABEL = 4; |
| private static final int RESET_LABEL = 5; |
| private static final int SUBMIT_LABEL = 6; |
| |
| 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; |
| |
| case DRAWABLEDIR: |
| // use one known resource to find the drawable directory |
| resid = com.android.internal.R.drawable.btn_check_off; |
| break; |
| |
| case FILE_UPLOAD_LABEL: |
| return mContext.getResources().getString( |
| com.android.internal.R.string.upload_file); |
| |
| case RESET_LABEL: |
| return mContext.getResources().getString( |
| com.android.internal.R.string.reset); |
| |
| case SUBMIT_LABEL: |
| return mContext.getResources().getString( |
| com.android.internal.R.string.submit); |
| |
| default: |
| Log.e(LOGTAG, "getRawResFilename got incompatible resource ID"); |
| return ""; |
| } |
| TypedValue value = new TypedValue(); |
| mContext.getResources().getValue(resid, value, true); |
| if (id == DRAWABLEDIR) { |
| String path = value.string.toString(); |
| int index = path.lastIndexOf('/'); |
| if (index < 0) { |
| Log.e(LOGTAG, "Can't find drawable directory."); |
| return ""; |
| } |
| return path.substring(0, index + 1); |
| } |
| return value.string.toString(); |
| } |
| |
| private float density() { |
| return mContext.getResources().getDisplayMetrics().density; |
| } |
| |
| //========================================================================== |
| // 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 nativePostUrl(String url, byte[] postData); |
| |
| private native void nativeLoadData(String baseUrl, String data, |
| String mimeType, String encoding, String failUrl); |
| |
| /** |
| * Stop loading the current page. |
| */ |
| public void stopLoading() { |
| if (mIsMainFrame) { |
| resetLoadingStates(); |
| } |
| nativeStopLoading(); |
| } |
| |
| private native void nativeStopLoading(); |
| |
| /** |
| * 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(); |
| |
| private native void nativeOrientationChanged(int orientation); |
| } |