• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.webkit;
18 
19 import android.app.ActivityManager;
20 import android.content.ComponentCallbacks;
21 import android.content.Context;
22 import android.content.res.AssetManager;
23 import android.content.res.Configuration;
24 import android.content.res.Resources;
25 import android.content.res.Resources.NotFoundException;
26 import android.graphics.Bitmap;
27 import android.net.ParseException;
28 import android.net.Uri;
29 import android.net.WebAddress;
30 import android.net.http.ErrorStrings;
31 import android.net.http.SslCertificate;
32 import android.net.http.SslError;
33 import android.os.Handler;
34 import android.os.Message;
35 import android.util.Log;
36 import android.util.TypedValue;
37 import android.view.Surface;
38 import android.view.ViewRootImpl;
39 import android.view.WindowManager;
40 
41 import junit.framework.Assert;
42 
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.lang.ref.WeakReference;
46 import java.net.URLEncoder;
47 import java.nio.charset.Charsets;
48 import java.security.PrivateKey;
49 import java.security.cert.CertificateEncodingException;
50 import java.security.cert.X509Certificate;
51 import java.util.ArrayList;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.Iterator;
55 import java.util.Map;
56 import java.util.Set;
57 
58 import org.apache.harmony.security.provider.cert.X509CertImpl;
59 import org.apache.harmony.xnet.provider.jsse.OpenSSLDSAPrivateKey;
60 import org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey;
61 
62 class BrowserFrame extends Handler {
63 
64     private static final String LOGTAG = "webkit";
65 
66     /**
67      * Cap the number of LoadListeners that will be instantiated, so
68      * we don't blow the GREF count.  Attempting to queue more than
69      * this many requests will prompt an error() callback on the
70      * request's LoadListener
71      */
72     private final static int MAX_OUTSTANDING_REQUESTS = 300;
73 
74     private final CallbackProxy mCallbackProxy;
75     private final WebSettingsClassic mSettings;
76     private final Context mContext;
77     private final WebViewDatabaseClassic mDatabase;
78     private final WebViewCore mWebViewCore;
79     /* package */ boolean mLoadInitFromJava;
80     private int mLoadType;
81     private boolean mFirstLayoutDone = true;
82     private boolean mCommitted = true;
83     // Flag for blocking messages. This is used during destroy() so
84     // that if the UI thread posts any messages after the message
85     // queue has been cleared,they are ignored.
86     private boolean mBlockMessages = false;
87     private int mOrientation = -1;
88 
89     // Is this frame the main frame?
90     private boolean mIsMainFrame;
91 
92     // Javascript interface object
93     private class JSObject {
94         Object object;
95         boolean requireAnnotation;
96 
JSObject(Object object, boolean requireAnnotation)97         public JSObject(Object object, boolean requireAnnotation) {
98             this.object = object;
99             this.requireAnnotation = requireAnnotation;
100         }
101     }
102 
103     // Attached Javascript interfaces
104     private Map<String, JSObject> mJavaScriptObjects;
105     private Set<Object> mRemovedJavaScriptObjects;
106 
107     // Key store handler when Chromium HTTP stack is used.
108     private KeyStoreHandler mKeyStoreHandler = null;
109 
110     // message ids
111     // a message posted when a frame loading is completed
112     static final int FRAME_COMPLETED = 1001;
113     // orientation change message
114     static final int ORIENTATION_CHANGED = 1002;
115     // a message posted when the user decides the policy
116     static final int POLICY_FUNCTION = 1003;
117 
118     // Note: need to keep these in sync with FrameLoaderTypes.h in native
119     static final int FRAME_LOADTYPE_STANDARD = 0;
120     static final int FRAME_LOADTYPE_BACK = 1;
121     static final int FRAME_LOADTYPE_FORWARD = 2;
122     static final int FRAME_LOADTYPE_INDEXEDBACKFORWARD = 3;
123     static final int FRAME_LOADTYPE_RELOAD = 4;
124     static final int FRAME_LOADTYPE_RELOADALLOWINGSTALEDATA = 5;
125     static final int FRAME_LOADTYPE_SAME = 6;
126     static final int FRAME_LOADTYPE_REDIRECT = 7;
127     static final int FRAME_LOADTYPE_REPLACE = 8;
128 
129     // A progress threshold to switch from history Picture to live Picture
130     private static final int TRANSITION_SWITCH_THRESHOLD = 75;
131 
132     // This is a field accessed by native code as well as package classes.
133     /*package*/ int mNativeFrame;
134 
135     // Static instance of a JWebCoreJavaBridge to handle timer and cookie
136     // requests from WebCore.
137     static JWebCoreJavaBridge sJavaBridge;
138 
139     private static class ConfigCallback implements ComponentCallbacks {
140         private final ArrayList<WeakReference<Handler>> mHandlers =
141                 new ArrayList<WeakReference<Handler>>();
142         private final WindowManager mWindowManager;
143 
ConfigCallback(WindowManager wm)144         ConfigCallback(WindowManager wm) {
145             mWindowManager = wm;
146         }
147 
addHandler(Handler h)148         public synchronized void addHandler(Handler h) {
149             // No need to ever remove a Handler. If the BrowserFrame is
150             // destroyed, it will be collected and the WeakReference set to
151             // null. If it happens to still be around during a configuration
152             // change, the message will be ignored.
153             mHandlers.add(new WeakReference<Handler>(h));
154         }
155 
onConfigurationChanged(Configuration newConfig)156         public void onConfigurationChanged(Configuration newConfig) {
157             if (mHandlers.size() == 0) {
158                 return;
159             }
160             int orientation =
161                     mWindowManager.getDefaultDisplay().getOrientation();
162             switch (orientation) {
163                 case Surface.ROTATION_90:
164                     orientation = 90;
165                     break;
166                 case Surface.ROTATION_180:
167                     orientation = 180;
168                     break;
169                 case Surface.ROTATION_270:
170                     orientation = -90;
171                     break;
172                 case Surface.ROTATION_0:
173                     orientation = 0;
174                     break;
175                 default:
176                     break;
177             }
178             synchronized (this) {
179                 // Create a list of handlers to remove. Go ahead and make it
180                 // the same size to avoid resizing.
181                 ArrayList<WeakReference> handlersToRemove =
182                         new ArrayList<WeakReference>(mHandlers.size());
183                 for (WeakReference<Handler> wh : mHandlers) {
184                     Handler h = wh.get();
185                     if (h != null) {
186                         h.sendMessage(h.obtainMessage(ORIENTATION_CHANGED,
187                                     orientation, 0));
188                     } else {
189                         handlersToRemove.add(wh);
190                     }
191                 }
192                 // Now remove all the null references.
193                 for (WeakReference weak : handlersToRemove) {
194                     mHandlers.remove(weak);
195                 }
196             }
197         }
198 
onLowMemory()199         public void onLowMemory() {}
200     }
201     static ConfigCallback sConfigCallback;
202 
203     /**
204      * Create a new BrowserFrame to be used in an application.
205      * @param context An application context to use when retrieving assets.
206      * @param w A WebViewCore used as the view for this frame.
207      * @param proxy A CallbackProxy for posting messages to the UI thread and
208      *              querying a client for information.
209      * @param settings A WebSettings object that holds all settings.
210      * XXX: Called by WebCore thread.
211      */
BrowserFrame(Context context, WebViewCore w, CallbackProxy proxy, WebSettingsClassic settings, Map<String, Object> javascriptInterfaces)212     public BrowserFrame(Context context, WebViewCore w, CallbackProxy proxy,
213             WebSettingsClassic settings, Map<String, Object> javascriptInterfaces) {
214 
215         Context appContext = context.getApplicationContext();
216 
217         // Create a global JWebCoreJavaBridge to handle timers and
218         // cookies in the WebCore thread.
219         if (sJavaBridge == null) {
220             sJavaBridge = new JWebCoreJavaBridge();
221             // set WebCore native cache size
222             ActivityManager am = (ActivityManager) context
223                     .getSystemService(Context.ACTIVITY_SERVICE);
224             if (am.getMemoryClass() > 16) {
225                 sJavaBridge.setCacheSize(8 * 1024 * 1024);
226             } else {
227                 sJavaBridge.setCacheSize(4 * 1024 * 1024);
228             }
229             // initialize CacheManager
230             CacheManager.init(appContext);
231             // create CookieSyncManager with current Context
232             CookieSyncManager.createInstance(appContext);
233             // create PluginManager with current Context
234             PluginManager.getInstance(appContext);
235         }
236 
237         if (sConfigCallback == null) {
238             sConfigCallback = new ConfigCallback(
239                     (WindowManager) appContext.getSystemService(
240                             Context.WINDOW_SERVICE));
241             ViewRootImpl.addConfigCallback(sConfigCallback);
242         }
243         sConfigCallback.addHandler(this);
244 
245         mJavaScriptObjects = new HashMap<String, JSObject>();
246         addJavaScriptObjects(javascriptInterfaces);
247         mRemovedJavaScriptObjects = new HashSet<Object>();
248 
249         mSettings = settings;
250         mContext = context;
251         mCallbackProxy = proxy;
252         mDatabase = WebViewDatabaseClassic.getInstance(appContext);
253         mWebViewCore = w;
254 
255         AssetManager am = context.getAssets();
256         nativeCreateFrame(w, am, proxy.getBackForwardList());
257 
258         if (DebugFlags.BROWSER_FRAME) {
259             Log.v(LOGTAG, "BrowserFrame constructor: this=" + this);
260         }
261     }
262 
263     /**
264      * Load a url from the network or the filesystem into the main frame.
265      * Following the same behaviour as Safari, javascript: URLs are not passed
266      * to the main frame, instead they are evaluated immediately.
267      * @param url The url to load.
268      * @param extraHeaders The extra headers sent with this url. This should not
269      *            include the common headers like "user-agent". If it does, it
270      *            will be replaced by the intrinsic value of the WebView.
271      */
loadUrl(String url, Map<String, String> extraHeaders)272     public void loadUrl(String url, Map<String, String> extraHeaders) {
273         mLoadInitFromJava = true;
274         if (URLUtil.isJavaScriptUrl(url)) {
275             // strip off the scheme and evaluate the string
276             stringByEvaluatingJavaScriptFromString(
277                     url.substring("javascript:".length()));
278         } else {
279             nativeLoadUrl(url, extraHeaders);
280         }
281         mLoadInitFromJava = false;
282     }
283 
284     /**
285      * Load a url with "POST" method from the network into the main frame.
286      * @param url The url to load.
287      * @param data The data for POST request.
288      */
postUrl(String url, byte[] data)289     public void postUrl(String url, byte[] data) {
290         mLoadInitFromJava = true;
291         nativePostUrl(url, data);
292         mLoadInitFromJava = false;
293     }
294 
295     /**
296      * Load the content as if it was loaded by the provided base URL. The
297      * historyUrl is used as the history entry for the load data.
298      *
299      * @param baseUrl Base URL used to resolve relative paths in the content
300      * @param data Content to render in the browser
301      * @param mimeType Mimetype of the data being passed in
302      * @param encoding Character set encoding of the provided data.
303      * @param historyUrl URL to use as the history entry.
304      */
loadData(String baseUrl, String data, String mimeType, String encoding, String historyUrl)305     public void loadData(String baseUrl, String data, String mimeType,
306             String encoding, String historyUrl) {
307         mLoadInitFromJava = true;
308         if (historyUrl == null || historyUrl.length() == 0) {
309             historyUrl = "about:blank";
310         }
311         if (data == null) {
312             data = "";
313         }
314 
315         // Setup defaults for missing values. These defaults where taken from
316         // WebKit's WebFrame.mm
317         if (baseUrl == null || baseUrl.length() == 0) {
318             baseUrl = "about:blank";
319         }
320         if (mimeType == null || mimeType.length() == 0) {
321             mimeType = "text/html";
322         }
323         nativeLoadData(baseUrl, data, mimeType, encoding, historyUrl);
324         mLoadInitFromJava = false;
325     }
326 
327     /**
328      * Saves the contents of the frame as a web archive.
329      *
330      * @param basename The filename where the archive should be placed.
331      * @param autoname If false, takes filename to be a file. If true, filename
332      *                 is assumed to be a directory in which a filename will be
333      *                 chosen according to the url of the current page.
334      */
saveWebArchive(String basename, boolean autoname)335     /* package */ String saveWebArchive(String basename, boolean autoname) {
336         return nativeSaveWebArchive(basename, autoname);
337     }
338 
339     /**
340      * Go back or forward the number of steps given.
341      * @param steps A negative or positive number indicating the direction
342      *              and number of steps to move.
343      */
goBackOrForward(int steps)344     public void goBackOrForward(int steps) {
345         mLoadInitFromJava = true;
346         nativeGoBackOrForward(steps);
347         mLoadInitFromJava = false;
348     }
349 
350     /**
351      * native callback
352      * Report an error to an activity.
353      * @param errorCode The HTTP error code.
354      * @param description Optional human-readable description. If no description
355      *     is given, we'll use a standard localized error message.
356      * @param failingUrl The URL that was being loaded when the error occurred.
357      * TODO: Report all errors including resource errors but include some kind
358      * of domain identifier. Change errorCode to an enum for a cleaner
359      * interface.
360      */
reportError(int errorCode, String description, String failingUrl)361     private void reportError(int errorCode, String description, String failingUrl) {
362         // As this is called for the main resource and loading will be stopped
363         // after, reset the state variables.
364         resetLoadingStates();
365         if (description == null || description.isEmpty()) {
366             description = ErrorStrings.getString(errorCode, mContext);
367         }
368         mCallbackProxy.onReceivedError(errorCode, description, failingUrl);
369     }
370 
resetLoadingStates()371     private void resetLoadingStates() {
372         mCommitted = true;
373         mFirstLayoutDone = true;
374     }
375 
committed()376     /* package */boolean committed() {
377         return mCommitted;
378     }
379 
firstLayoutDone()380     /* package */boolean firstLayoutDone() {
381         return mFirstLayoutDone;
382     }
383 
loadType()384     /* package */int loadType() {
385         return mLoadType;
386     }
387 
didFirstLayout()388     /* package */void didFirstLayout() {
389         if (!mFirstLayoutDone) {
390             mFirstLayoutDone = true;
391             // ensure {@link WebViewCore#webkitDraw} is called as we were
392             // blocking the update in {@link #loadStarted}
393             mWebViewCore.contentDraw();
394         }
395     }
396 
397     /**
398      * native callback
399      * Indicates the beginning of a new load.
400      * This method will be called once for the main frame.
401      */
loadStarted(String url, Bitmap favicon, int loadType, boolean isMainFrame)402     private void loadStarted(String url, Bitmap favicon, int loadType,
403             boolean isMainFrame) {
404         mIsMainFrame = isMainFrame;
405 
406         if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
407             mLoadType = loadType;
408 
409             if (isMainFrame) {
410                 // Call onPageStarted for main frames.
411                 mCallbackProxy.onPageStarted(url, favicon);
412                 // as didFirstLayout() is only called for the main frame, reset
413                 // mFirstLayoutDone only for the main frames
414                 mFirstLayoutDone = false;
415                 mCommitted = false;
416                 // remove pending draw to block update until mFirstLayoutDone is
417                 // set to true in didFirstLayout()
418                 mWebViewCore.clearContent();
419                 mWebViewCore.removeMessages(WebViewCore.EventHub.WEBKIT_DRAW);
420             }
421         }
422     }
423 
424     @SuppressWarnings("unused")
saveFormData(HashMap<String, String> data)425     private void saveFormData(HashMap<String, String> data) {
426         if (mSettings.getSaveFormData()) {
427             final WebHistoryItem h = mCallbackProxy.getBackForwardList()
428                     .getCurrentItem();
429             if (h != null) {
430                 String url = WebTextView.urlForAutoCompleteData(h.getUrl());
431                 if (url != null) {
432                     mDatabase.setFormData(url, data);
433                 }
434             }
435         }
436     }
437 
438     @SuppressWarnings("unused")
shouldSaveFormData()439     private boolean shouldSaveFormData() {
440         if (mSettings.getSaveFormData()) {
441             final WebHistoryItem h = mCallbackProxy.getBackForwardList()
442                     .getCurrentItem();
443             return h != null && h.getUrl() != null;
444         }
445         return false;
446     }
447 
448     /**
449      * native callback
450      * Indicates the WebKit has committed to the new load
451      */
transitionToCommitted(int loadType, boolean isMainFrame)452     private void transitionToCommitted(int loadType, boolean isMainFrame) {
453         // loadType is not used yet
454         if (isMainFrame) {
455             mCommitted = true;
456             mWebViewCore.getWebViewClassic().mViewManager.postResetStateAll();
457         }
458     }
459 
460     /**
461      * native callback
462      * <p>
463      * Indicates the end of a new load.
464      * This method will be called once for the main frame.
465      */
loadFinished(String url, int loadType, boolean isMainFrame)466     private void loadFinished(String url, int loadType, boolean isMainFrame) {
467         // mIsMainFrame and isMainFrame are better be equal!!!
468 
469         if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
470             if (isMainFrame) {
471                 resetLoadingStates();
472                 mCallbackProxy.switchOutDrawHistory();
473                 mCallbackProxy.onPageFinished(url);
474             }
475         }
476     }
477 
478     /**
479      * Destroy all native components of the BrowserFrame.
480      */
destroy()481     public void destroy() {
482         nativeDestroyFrame();
483         mBlockMessages = true;
484         removeCallbacksAndMessages(null);
485     }
486 
487     /**
488      * Handle messages posted to us.
489      * @param msg The message to handle.
490      */
491     @Override
handleMessage(Message msg)492     public void handleMessage(Message msg) {
493         if (mBlockMessages) {
494             return;
495         }
496         switch (msg.what) {
497             case FRAME_COMPLETED: {
498                 if (mSettings.getSavePassword() && hasPasswordField()) {
499                     WebHistoryItem item = mCallbackProxy.getBackForwardList()
500                             .getCurrentItem();
501                     if (item != null) {
502                         WebAddress uri = new WebAddress(item.getUrl());
503                         String schemePlusHost = uri.getScheme() + uri.getHost();
504                         String[] up = mDatabase.getUsernamePassword(
505                                 schemePlusHost);
506                         if (up != null && up[0] != null) {
507                             setUsernamePassword(up[0], up[1]);
508                         }
509                     }
510                 }
511                 break;
512             }
513 
514             case POLICY_FUNCTION: {
515                 nativeCallPolicyFunction(msg.arg1, msg.arg2);
516                 break;
517             }
518 
519             case ORIENTATION_CHANGED: {
520                 if (mOrientation != msg.arg1) {
521                     mOrientation = msg.arg1;
522                     nativeOrientationChanged(msg.arg1);
523                 }
524                 break;
525             }
526 
527             default:
528                 break;
529         }
530     }
531 
532     /**
533      * Punch-through for WebCore to set the document
534      * title. Inform the Activity of the new title.
535      * @param title The new title of the document.
536      */
setTitle(String title)537     private void setTitle(String title) {
538         // FIXME: The activity must call getTitle (a native method) to get the
539         // title. We should try and cache the title if we can also keep it in
540         // sync with the document.
541         mCallbackProxy.onReceivedTitle(title);
542     }
543 
544     /**
545      * Retrieves the render tree of this frame and puts it as the object for
546      * the message and sends the message.
547      * @param callback the message to use to send the render tree
548      */
externalRepresentation(Message callback)549     public void externalRepresentation(Message callback) {
550         callback.obj = externalRepresentation();;
551         callback.sendToTarget();
552     }
553 
554     /**
555      * Return the render tree as a string
556      */
externalRepresentation()557     private native String externalRepresentation();
558 
559     /**
560      * Retrieves the visual text of the frames, puts it as the object for
561      * the message and sends the message.
562      * @param callback the message to use to send the visual text
563      */
documentAsText(Message callback)564     public void documentAsText(Message callback) {
565         StringBuilder text = new StringBuilder();
566         if (callback.arg1 != 0) {
567             // Dump top frame as text.
568             text.append(documentAsText());
569         }
570         if (callback.arg2 != 0) {
571             // Dump child frames as text.
572             text.append(childFramesAsText());
573         }
574         callback.obj = text.toString();
575         callback.sendToTarget();
576     }
577 
578     /**
579      * Return the text drawn on the screen as a string
580      */
documentAsText()581     private native String documentAsText();
582 
583     /**
584      * Return the text drawn on the child frames as a string
585      */
childFramesAsText()586     private native String childFramesAsText();
587 
588     /*
589      * This method is called by WebCore to inform the frame that
590      * the Javascript window object has been cleared.
591      * We should re-attach any attached js interfaces.
592      */
windowObjectCleared(int nativeFramePointer)593     private void windowObjectCleared(int nativeFramePointer) {
594         Iterator<String> iter = mJavaScriptObjects.keySet().iterator();
595         while (iter.hasNext())  {
596             String interfaceName = iter.next();
597             JSObject jsobject = mJavaScriptObjects.get(interfaceName);
598             if (jsobject != null && jsobject.object != null) {
599                 nativeAddJavascriptInterface(nativeFramePointer,
600                         jsobject.object, interfaceName, jsobject.requireAnnotation);
601             }
602         }
603         mRemovedJavaScriptObjects.clear();
604     }
605 
606     /*
607      * Add javascript objects to the internal list of objects. The default behavior
608      * is to allow access to inherited methods (no annotation needed). This is only
609      * used when js objects are passed through a constructor (via a hidden constructor).
610      *
611      * @TODO change the default behavior to be compatible with the public addjavascriptinterface
612      */
addJavaScriptObjects(Map<String, Object> javascriptInterfaces)613     private void addJavaScriptObjects(Map<String, Object> javascriptInterfaces) {
614 
615         // TODO in a separate CL provide logic to enable annotations for API level JB_MR1 and above.
616         if (javascriptInterfaces == null) return;
617         Iterator<String> iter = javascriptInterfaces.keySet().iterator();
618         while (iter.hasNext())  {
619             String interfaceName = iter.next();
620             Object object = javascriptInterfaces.get(interfaceName);
621             if (object != null) {
622                 mJavaScriptObjects.put(interfaceName, new JSObject(object, false));
623             }
624         }
625     }
626 
627     /**
628      * This method is called by WebCore to check whether application
629      * wants to hijack url loading
630      */
handleUrl(String url)631     public boolean handleUrl(String url) {
632         if (mLoadInitFromJava == true) {
633             return false;
634         }
635         if (mCallbackProxy.shouldOverrideUrlLoading(url)) {
636             // if the url is hijacked, reset the state of the BrowserFrame
637             didFirstLayout();
638             return true;
639         } else {
640             return false;
641         }
642     }
643 
addJavascriptInterface(Object obj, String interfaceName, boolean requireAnnotation)644     public void addJavascriptInterface(Object obj, String interfaceName,
645             boolean requireAnnotation) {
646         assert obj != null;
647         removeJavascriptInterface(interfaceName);
648         mJavaScriptObjects.put(interfaceName, new JSObject(obj, requireAnnotation));
649     }
650 
removeJavascriptInterface(String interfaceName)651     public void removeJavascriptInterface(String interfaceName) {
652         // We keep a reference to the removed object because the native side holds only a weak
653         // reference and we need to allow the object to continue to be used until the page has been
654         // navigated.
655         if (mJavaScriptObjects.containsKey(interfaceName)) {
656             mRemovedJavaScriptObjects.add(mJavaScriptObjects.remove(interfaceName));
657         }
658     }
659 
660     /**
661      * Called by JNI.  Given a URI, find the associated file and return its size
662      * @param uri A String representing the URI of the desired file.
663      * @return int The size of the given file.
664      */
getFileSize(String uri)665     private int getFileSize(String uri) {
666         int size = 0;
667         try {
668             InputStream stream = mContext.getContentResolver()
669                             .openInputStream(Uri.parse(uri));
670             size = stream.available();
671             stream.close();
672         } catch (Exception e) {}
673         return size;
674     }
675 
676     /**
677      * Called by JNI.  Given a URI, a buffer, and an offset into the buffer,
678      * copy the resource into buffer.
679      * @param uri A String representing the URI of the desired file.
680      * @param buffer The byte array to copy the data into.
681      * @param offset The offet into buffer to place the data.
682      * @param expectedSize The size that the buffer has allocated for this file.
683      * @return int The size of the given file, or zero if it fails.
684      */
getFile(String uri, byte[] buffer, int offset, int expectedSize)685     private int getFile(String uri, byte[] buffer, int offset,
686             int expectedSize) {
687         int size = 0;
688         try {
689             InputStream stream = mContext.getContentResolver()
690                             .openInputStream(Uri.parse(uri));
691             size = stream.available();
692             if (size <= expectedSize && buffer != null
693                     && buffer.length - offset >= size) {
694                 stream.read(buffer, offset, size);
695             } else {
696                 size = 0;
697             }
698             stream.close();
699         } catch (java.io.FileNotFoundException e) {
700             Log.e(LOGTAG, "FileNotFoundException:" + e);
701             size = 0;
702         } catch (java.io.IOException e2) {
703             Log.e(LOGTAG, "IOException: " + e2);
704             size = 0;
705         }
706         return size;
707     }
708 
709     /**
710      * Get the InputStream for an Android resource
711      * There are three different kinds of android resources:
712      * - file:///android_res
713      * - file:///android_asset
714      * - content://
715      * @param url The url to load.
716      * @return An InputStream to the android resource
717      */
inputStreamForAndroidResource(String url)718     private InputStream inputStreamForAndroidResource(String url) {
719         final String ANDROID_ASSET = URLUtil.ASSET_BASE;
720         final String ANDROID_RESOURCE = URLUtil.RESOURCE_BASE;
721         final String ANDROID_CONTENT = URLUtil.CONTENT_BASE;
722 
723         if (url.startsWith(ANDROID_RESOURCE)) {
724             url = url.replaceFirst(ANDROID_RESOURCE, "");
725             if (url == null || url.length() == 0) {
726                 Log.e(LOGTAG, "url has length 0 " + url);
727                 return null;
728             }
729             int slash = url.indexOf('/');
730             int dot = url.indexOf('.', slash);
731             if (slash == -1 || dot == -1) {
732                 Log.e(LOGTAG, "Incorrect res path: " + url);
733                 return null;
734             }
735             String subClassName = url.substring(0, slash);
736             String fieldName = url.substring(slash + 1, dot);
737             String errorMsg = null;
738             try {
739                 final Class<?> d = mContext.getApplicationContext()
740                         .getClassLoader().loadClass(
741                                 mContext.getPackageName() + ".R$"
742                                         + subClassName);
743                 final java.lang.reflect.Field field = d.getField(fieldName);
744                 final int id = field.getInt(null);
745                 TypedValue value = new TypedValue();
746                 mContext.getResources().getValue(id, value, true);
747                 if (value.type == TypedValue.TYPE_STRING) {
748                     return mContext.getAssets().openNonAsset(
749                             value.assetCookie, value.string.toString(),
750                             AssetManager.ACCESS_STREAMING);
751                 } else {
752                     // Old stack only supports TYPE_STRING for res files
753                     Log.e(LOGTAG, "not of type string: " + url);
754                     return null;
755                 }
756             } catch (Exception e) {
757                 Log.e(LOGTAG, "Exception: " + url);
758                 return null;
759             }
760         } else if (url.startsWith(ANDROID_ASSET)) {
761             url = url.replaceFirst(ANDROID_ASSET, "");
762             try {
763                 AssetManager assets = mContext.getAssets();
764                 Uri uri = Uri.parse(url);
765                 return assets.open(uri.getPath(), AssetManager.ACCESS_STREAMING);
766             } catch (IOException e) {
767                 return null;
768             }
769         } else if (mSettings.getAllowContentAccess() &&
770                    url.startsWith(ANDROID_CONTENT)) {
771             try {
772                 // Strip off MIME type. If we don't do this, we can fail to
773                 // load Gmail attachments, because the URL being loaded doesn't
774                 // exactly match the URL we have permission to read.
775                 int mimeIndex = url.lastIndexOf('?');
776                 if (mimeIndex != -1) {
777                     url = url.substring(0, mimeIndex);
778                 }
779                 Uri uri = Uri.parse(url);
780                 return mContext.getContentResolver().openInputStream(uri);
781             } catch (Exception e) {
782                 Log.e(LOGTAG, "Exception: " + url);
783                 return null;
784             }
785         } else {
786             return null;
787         }
788     }
789 
790     /**
791      * If this looks like a POST request (form submission) containing a username
792      * and password, give the user the option of saving them. Will either do
793      * nothing, or block until the UI interaction is complete.
794      *
795      * Called directly by WebKit.
796      *
797      * @param postData The data about to be sent as the body of a POST request.
798      * @param username The username entered by the user (sniffed from the DOM).
799      * @param password The password entered by the user (sniffed from the DOM).
800      */
maybeSavePassword( byte[] postData, String username, String password)801     private void maybeSavePassword(
802             byte[] postData, String username, String password) {
803         if (postData == null
804                 || username == null || username.isEmpty()
805                 || password == null || password.isEmpty()) {
806             return; // No password to save.
807         }
808 
809         if (!mSettings.getSavePassword()) {
810             return; // User doesn't want to save passwords.
811         }
812 
813         try {
814             if (DebugFlags.BROWSER_FRAME) {
815                 Assert.assertNotNull(mCallbackProxy.getBackForwardList()
816                         .getCurrentItem());
817             }
818             WebAddress uri = new WebAddress(mCallbackProxy
819                     .getBackForwardList().getCurrentItem().getUrl());
820             String schemePlusHost = uri.getScheme() + uri.getHost();
821             // Check to see if the username & password appear in
822             // the post data (there could be another form on the
823             // page and that was posted instead.
824             String postString = new String(postData);
825             if (postString.contains(URLEncoder.encode(username)) &&
826                     postString.contains(URLEncoder.encode(password))) {
827                 String[] saved = mDatabase.getUsernamePassword(
828                         schemePlusHost);
829                 if (saved != null) {
830                     // null username implies that user has chosen not to
831                     // save password
832                     if (saved[0] != null) {
833                         // non-null username implies that user has
834                         // chosen to save password, so update the
835                         // recorded password
836                         mDatabase.setUsernamePassword(schemePlusHost, username, password);
837                     }
838                 } else {
839                     // CallbackProxy will handle creating the resume
840                     // message
841                     mCallbackProxy.onSavePassword(schemePlusHost, username,
842                             password, null);
843                 }
844             }
845         } catch (ParseException ex) {
846             // if it is bad uri, don't save its password
847         }
848     }
849 
850     // Called by jni from the chrome network stack.
shouldInterceptRequest(String url)851     private WebResourceResponse shouldInterceptRequest(String url) {
852         InputStream androidResource = inputStreamForAndroidResource(url);
853         if (androidResource != null) {
854             return new WebResourceResponse(null, null, androidResource);
855         }
856 
857         // Note that we check this after looking for an android_asset or
858         // android_res URL, as we allow those even if file access is disabled.
859         if (!mSettings.getAllowFileAccess() && url.startsWith("file://")) {
860             return new WebResourceResponse(null, null, null);
861         }
862 
863         WebResourceResponse response = mCallbackProxy.shouldInterceptRequest(url);
864         if (response == null && "browser:incognito".equals(url)) {
865             try {
866                 Resources res = mContext.getResources();
867                 InputStream ins = res.openRawResource(
868                         com.android.internal.R.raw.incognito_mode_start_page);
869                 response = new WebResourceResponse("text/html", "utf8", ins);
870             } catch (NotFoundException ex) {
871                 // This shouldn't happen, but try and gracefully handle it jic
872                 Log.w(LOGTAG, "Failed opening raw.incognito_mode_start_page", ex);
873             }
874         }
875         return response;
876     }
877 
878     /**
879      * Set the progress for the browser activity.  Called by native code.
880      * Uses a delay so it does not happen too often.
881      * @param newProgress An int between zero and one hundred representing
882      *                    the current progress percentage of loading the page.
883      */
setProgress(int newProgress)884     private void setProgress(int newProgress) {
885         mCallbackProxy.onProgressChanged(newProgress);
886         if (newProgress == 100) {
887             sendMessageDelayed(obtainMessage(FRAME_COMPLETED), 100);
888         }
889         // FIXME: Need to figure out a better way to switch out of the history
890         // drawing mode. Maybe we can somehow compare the history picture with
891         // the current picture, and switch when it contains more content.
892         if (mFirstLayoutDone && newProgress > TRANSITION_SWITCH_THRESHOLD) {
893             mCallbackProxy.switchOutDrawHistory();
894         }
895     }
896 
897     /**
898      * Send the icon to the activity for display.
899      * @param icon A Bitmap representing a page's favicon.
900      */
didReceiveIcon(Bitmap icon)901     private void didReceiveIcon(Bitmap icon) {
902         mCallbackProxy.onReceivedIcon(icon);
903     }
904 
905     // Called by JNI when an apple-touch-icon attribute was found.
didReceiveTouchIconUrl(String url, boolean precomposed)906     private void didReceiveTouchIconUrl(String url, boolean precomposed) {
907         mCallbackProxy.onReceivedTouchIconUrl(url, precomposed);
908     }
909 
910     /**
911      * Request a new window from the client.
912      * @return The BrowserFrame object stored in the new WebView.
913      */
createWindow(boolean dialog, boolean userGesture)914     private BrowserFrame createWindow(boolean dialog, boolean userGesture) {
915         return mCallbackProxy.createWindow(dialog, userGesture);
916     }
917 
918     /**
919      * Try to focus this WebView.
920      */
requestFocus()921     private void requestFocus() {
922         mCallbackProxy.onRequestFocus();
923     }
924 
925     /**
926      * Close this frame and window.
927      */
closeWindow(WebViewCore w)928     private void closeWindow(WebViewCore w) {
929         mCallbackProxy.onCloseWindow(w.getWebViewClassic());
930     }
931 
932     // XXX: Must match PolicyAction in FrameLoaderTypes.h in webcore
933     static final int POLICY_USE = 0;
934     static final int POLICY_IGNORE = 2;
935 
decidePolicyForFormResubmission(int policyFunction)936     private void decidePolicyForFormResubmission(int policyFunction) {
937         Message dontResend = obtainMessage(POLICY_FUNCTION, policyFunction,
938                 POLICY_IGNORE);
939         Message resend = obtainMessage(POLICY_FUNCTION, policyFunction,
940                 POLICY_USE);
941         mCallbackProxy.onFormResubmission(dontResend, resend);
942     }
943 
944     /**
945      * Tell the activity to update its global history.
946      */
updateVisitedHistory(String url, boolean isReload)947     private void updateVisitedHistory(String url, boolean isReload) {
948         mCallbackProxy.doUpdateVisitedHistory(url, isReload);
949     }
950 
951     /**
952      * Get the CallbackProxy for sending messages to the UI thread.
953      */
getCallbackProxy()954     /* package */ CallbackProxy getCallbackProxy() {
955         return mCallbackProxy;
956     }
957 
958     /**
959      * Returns the User Agent used by this frame
960      */
getUserAgentString()961     String getUserAgentString() {
962         return mSettings.getUserAgentString();
963     }
964 
965     // These ids need to be in sync with enum rawResId in PlatformBridge.h
966     private static final int NODOMAIN = 1;
967     private static final int LOADERROR = 2;
968     /* package */ static final int DRAWABLEDIR = 3;
969     private static final int FILE_UPLOAD_LABEL = 4;
970     private static final int RESET_LABEL = 5;
971     private static final int SUBMIT_LABEL = 6;
972     private static final int FILE_UPLOAD_NO_FILE_CHOSEN = 7;
973 
getRawResFilename(int id)974     private String getRawResFilename(int id) {
975         return getRawResFilename(id, mContext);
976     }
getRawResFilename(int id, Context context)977     /* package */ static String getRawResFilename(int id, Context context) {
978         int resid;
979         switch (id) {
980             case NODOMAIN:
981                 resid = com.android.internal.R.raw.nodomain;
982                 break;
983 
984             case LOADERROR:
985                 resid = com.android.internal.R.raw.loaderror;
986                 break;
987 
988             case DRAWABLEDIR:
989                 // use one known resource to find the drawable directory
990                 resid = com.android.internal.R.drawable.btn_check_off;
991                 break;
992 
993             case FILE_UPLOAD_LABEL:
994                 return context.getResources().getString(
995                         com.android.internal.R.string.upload_file);
996 
997             case RESET_LABEL:
998                 return context.getResources().getString(
999                         com.android.internal.R.string.reset);
1000 
1001             case SUBMIT_LABEL:
1002                 return context.getResources().getString(
1003                         com.android.internal.R.string.submit);
1004 
1005             case FILE_UPLOAD_NO_FILE_CHOSEN:
1006                 return context.getResources().getString(
1007                         com.android.internal.R.string.no_file_chosen);
1008 
1009             default:
1010                 Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
1011                 return "";
1012         }
1013         TypedValue value = new TypedValue();
1014         context.getResources().getValue(resid, value, true);
1015         if (id == DRAWABLEDIR) {
1016             String path = value.string.toString();
1017             int index = path.lastIndexOf('/');
1018             if (index < 0) {
1019                 Log.e(LOGTAG, "Can't find drawable directory.");
1020                 return "";
1021             }
1022             return path.substring(0, index + 1);
1023         }
1024         return value.string.toString();
1025     }
1026 
density()1027     private float density() {
1028         return WebViewCore.getFixedDisplayDensity(mContext);
1029     }
1030 
1031     /**
1032      * Called by JNI when the native HTTP stack gets an authentication request.
1033      *
1034      * We delegate the request to CallbackProxy, and route its response to
1035      * {@link #nativeAuthenticationProceed(int, String, String)} or
1036      * {@link #nativeAuthenticationCancel(int)}.
1037      *
1038      * We don't care what thread the callback is invoked on. All threading is
1039      * handled on the C++ side, because the WebKit thread may be blocked on a
1040      * synchronous call and unable to pump our MessageQueue.
1041      */
didReceiveAuthenticationChallenge( final int handle, String host, String realm, final boolean useCachedCredentials, final boolean suppressDialog)1042     private void didReceiveAuthenticationChallenge(
1043             final int handle, String host, String realm, final boolean useCachedCredentials,
1044             final boolean suppressDialog) {
1045 
1046         HttpAuthHandler handler = new HttpAuthHandler() {
1047 
1048             @Override
1049             public boolean useHttpAuthUsernamePassword() {
1050                 return useCachedCredentials;
1051             }
1052 
1053             @Override
1054             public void proceed(String username, String password) {
1055                 nativeAuthenticationProceed(handle, username, password);
1056             }
1057 
1058             @Override
1059             public void cancel() {
1060                 nativeAuthenticationCancel(handle);
1061             }
1062 
1063             @Override
1064             public boolean suppressDialog() {
1065                 return suppressDialog;
1066             }
1067         };
1068         mCallbackProxy.onReceivedHttpAuthRequest(handler, host, realm);
1069     }
1070 
1071     /**
1072      * Called by JNI when the Chromium HTTP stack gets an invalid certificate chain.
1073      *
1074      * We delegate the request to CallbackProxy, and route its response to
1075      * {@link #nativeSslCertErrorProceed(int)} or
1076      * {@link #nativeSslCertErrorCancel(int, int)}.
1077      */
reportSslCertError(final int handle, final int certError, byte certDER[], String url)1078     private void reportSslCertError(final int handle, final int certError, byte certDER[],
1079             String url) {
1080         final SslError sslError;
1081         try {
1082             X509Certificate cert = new X509CertImpl(certDER);
1083             SslCertificate sslCert = new SslCertificate(cert);
1084             sslError = SslError.SslErrorFromChromiumErrorCode(certError, sslCert, url);
1085         } catch (IOException e) {
1086             // Can't get the certificate, not much to do.
1087             Log.e(LOGTAG, "Can't get the certificate from WebKit, canceling");
1088             nativeSslCertErrorCancel(handle, certError);
1089             return;
1090         }
1091 
1092         if (SslCertLookupTable.getInstance().isAllowed(sslError)) {
1093             nativeSslCertErrorProceed(handle);
1094             mCallbackProxy.onProceededAfterSslError(sslError);
1095             return;
1096         }
1097 
1098         SslErrorHandler handler = new SslErrorHandler() {
1099             @Override
1100             public void proceed() {
1101                 SslCertLookupTable.getInstance().setIsAllowed(sslError);
1102                 post(new Runnable() {
1103                         public void run() {
1104                             nativeSslCertErrorProceed(handle);
1105                         }
1106                     });
1107             }
1108             @Override
1109             public void cancel() {
1110                 post(new Runnable() {
1111                         public void run() {
1112                             nativeSslCertErrorCancel(handle, certError);
1113                         }
1114                     });
1115             }
1116         };
1117         mCallbackProxy.onReceivedSslError(handler, sslError);
1118     }
1119 
1120     /**
1121      * Called by JNI when the native HTTPS stack gets a client
1122      * certificate request.
1123      *
1124      * We delegate the request to CallbackProxy, and route its response to
1125      * {@link #nativeSslClientCert(int, X509Certificate)}.
1126      */
requestClientCert(int handle, String hostAndPort)1127     private void requestClientCert(int handle, String hostAndPort) {
1128         SslClientCertLookupTable table = SslClientCertLookupTable.getInstance();
1129         if (table.IsAllowed(hostAndPort)) {
1130             // previously allowed
1131             PrivateKey pkey = table.PrivateKey(hostAndPort);
1132             if (pkey instanceof OpenSSLRSAPrivateKey) {
1133                 nativeSslClientCert(handle,
1134                                     ((OpenSSLRSAPrivateKey)pkey).getPkeyContext(),
1135                                     table.CertificateChain(hostAndPort));
1136             } else if (pkey instanceof OpenSSLDSAPrivateKey) {
1137                 nativeSslClientCert(handle,
1138                                     ((OpenSSLDSAPrivateKey)pkey).getPkeyContext(),
1139                                     table.CertificateChain(hostAndPort));
1140             } else {
1141                 nativeSslClientCert(handle,
1142                                     pkey.getEncoded(),
1143                                     table.CertificateChain(hostAndPort));
1144             }
1145         } else if (table.IsDenied(hostAndPort)) {
1146             // previously denied
1147             nativeSslClientCert(handle, 0, null);
1148         } else {
1149             // previously ignored or new
1150             mCallbackProxy.onReceivedClientCertRequest(
1151                     new ClientCertRequestHandler(this, handle, hostAndPort, table), hostAndPort);
1152         }
1153     }
1154 
1155     /**
1156      * Called by JNI when the native HTTP stack needs to download a file.
1157      *
1158      * We delegate the request to CallbackProxy, which owns the current app's
1159      * DownloadListener.
1160      */
downloadStart(String url, String userAgent, String contentDisposition, String mimeType, String referer, long contentLength)1161     private void downloadStart(String url, String userAgent,
1162             String contentDisposition, String mimeType, String referer, long contentLength) {
1163         // This will only work if the url ends with the filename
1164         if (mimeType.isEmpty()) {
1165             try {
1166                 String extension = url.substring(url.lastIndexOf('.') + 1);
1167                 mimeType = libcore.net.MimeUtils.guessMimeTypeFromExtension(extension);
1168                 // MimeUtils might return null, not sure if downloadmanager is happy with that
1169                 if (mimeType == null)
1170                     mimeType = "";
1171             } catch(IndexOutOfBoundsException exception) {
1172                 // mimeType string end with a '.', not much to do
1173             }
1174         }
1175         mimeType = MimeTypeMap.getSingleton().remapGenericMimeType(
1176                 mimeType, url, contentDisposition);
1177 
1178         if (CertTool.getCertType(mimeType) != null) {
1179             mKeyStoreHandler = new KeyStoreHandler(mimeType);
1180         } else {
1181             mCallbackProxy.onDownloadStart(url, userAgent,
1182                 contentDisposition, mimeType, referer, contentLength);
1183         }
1184     }
1185 
1186     /**
1187      * Called by JNI for Chrome HTTP stack when the Java side needs to access the data.
1188      */
didReceiveData(byte data[], int size)1189     private void didReceiveData(byte data[], int size) {
1190         if (mKeyStoreHandler != null) mKeyStoreHandler.didReceiveData(data, size);
1191     }
1192 
didFinishLoading()1193     private void didFinishLoading() {
1194       if (mKeyStoreHandler != null) {
1195           mKeyStoreHandler.installCert(mContext);
1196           mKeyStoreHandler = null;
1197       }
1198     }
1199 
1200     /**
1201      * Called by JNI when we recieve a certificate for the page's main resource.
1202      * Used by the Chromium HTTP stack only.
1203      */
setCertificate(byte cert_der[])1204     private void setCertificate(byte cert_der[]) {
1205         try {
1206             X509Certificate cert = new X509CertImpl(cert_der);
1207             mCallbackProxy.onReceivedCertificate(new SslCertificate(cert));
1208         } catch (IOException e) {
1209             // Can't get the certificate, not much to do.
1210             Log.e(LOGTAG, "Can't get the certificate from WebKit, canceling");
1211             return;
1212         }
1213     }
1214 
1215     /**
1216      * Called by JNI when processing the X-Auto-Login header.
1217      */
autoLogin(String realm, String account, String args)1218     private void autoLogin(String realm, String account, String args) {
1219         mCallbackProxy.onReceivedLoginRequest(realm, account, args);
1220     }
1221 
1222     //==========================================================================
1223     // native functions
1224     //==========================================================================
1225 
1226     /**
1227      * Create a new native frame for a given WebView
1228      * @param w     A WebView that the frame draws into.
1229      * @param am    AssetManager to use to get assets.
1230      * @param list  The native side will add and remove items from this list as
1231      *              the native list changes.
1232      */
nativeCreateFrame(WebViewCore w, AssetManager am, WebBackForwardList list)1233     private native void nativeCreateFrame(WebViewCore w, AssetManager am,
1234             WebBackForwardList list);
1235 
1236     /**
1237      * Destroy the native frame.
1238      */
nativeDestroyFrame()1239     public native void nativeDestroyFrame();
1240 
nativeCallPolicyFunction(int policyFunction, int decision)1241     private native void nativeCallPolicyFunction(int policyFunction,
1242             int decision);
1243 
1244     /**
1245      * Reload the current main frame.
1246      */
reload(boolean allowStale)1247     public native void reload(boolean allowStale);
1248 
1249     /**
1250      * Go back or forward the number of steps given.
1251      * @param steps A negative or positive number indicating the direction
1252      *              and number of steps to move.
1253      */
nativeGoBackOrForward(int steps)1254     private native void nativeGoBackOrForward(int steps);
1255 
1256     /**
1257      * stringByEvaluatingJavaScriptFromString will execute the
1258      * JS passed in in the context of this browser frame.
1259      * @param script A javascript string to execute
1260      *
1261      * @return string result of execution or null
1262      */
stringByEvaluatingJavaScriptFromString(String script)1263     public native String stringByEvaluatingJavaScriptFromString(String script);
1264 
1265     /**
1266      * Add a javascript interface to the main frame.
1267      */
nativeAddJavascriptInterface(int nativeFramePointer, Object obj, String interfaceName, boolean requireAnnotation)1268     private native void nativeAddJavascriptInterface(int nativeFramePointer,
1269             Object obj, String interfaceName, boolean requireAnnotation);
1270 
clearCache()1271     public native void clearCache();
1272 
1273     /**
1274      * Returns false if the url is bad.
1275      */
nativeLoadUrl(String url, Map<String, String> headers)1276     private native void nativeLoadUrl(String url, Map<String, String> headers);
1277 
nativePostUrl(String url, byte[] postData)1278     private native void nativePostUrl(String url, byte[] postData);
1279 
nativeLoadData(String baseUrl, String data, String mimeType, String encoding, String historyUrl)1280     private native void nativeLoadData(String baseUrl, String data,
1281             String mimeType, String encoding, String historyUrl);
1282 
1283     /**
1284      * Stop loading the current page.
1285      */
stopLoading()1286     public void stopLoading() {
1287         if (mIsMainFrame) {
1288             resetLoadingStates();
1289         }
1290         nativeStopLoading();
1291     }
1292 
nativeStopLoading()1293     private native void nativeStopLoading();
1294 
1295     /**
1296      * Return true if the document has images.
1297      */
documentHasImages()1298     public native boolean documentHasImages();
1299 
1300     /**
1301      * @return TRUE if there is a password field in the current frame
1302      */
hasPasswordField()1303     private native boolean hasPasswordField();
1304 
1305     /**
1306      * Get username and password in the current frame. If found, String[0] is
1307      * username and String[1] is password. Otherwise return NULL.
1308      * @return String[]
1309      */
getUsernamePassword()1310     private native String[] getUsernamePassword();
1311 
1312     /**
1313      * Set username and password to the proper fields in the current frame
1314      * @param username
1315      * @param password
1316      */
setUsernamePassword(String username, String password)1317     private native void setUsernamePassword(String username, String password);
1318 
nativeSaveWebArchive(String basename, boolean autoname)1319     private native String nativeSaveWebArchive(String basename, boolean autoname);
1320 
nativeOrientationChanged(int orientation)1321     private native void nativeOrientationChanged(int orientation);
1322 
nativeAuthenticationProceed(int handle, String username, String password)1323     private native void nativeAuthenticationProceed(int handle, String username, String password);
nativeAuthenticationCancel(int handle)1324     private native void nativeAuthenticationCancel(int handle);
1325 
nativeSslCertErrorProceed(int handle)1326     private native void nativeSslCertErrorProceed(int handle);
nativeSslCertErrorCancel(int handle, int certError)1327     private native void nativeSslCertErrorCancel(int handle, int certError);
1328 
nativeSslClientCert(int handle, int ctx, byte[][] asn1DerEncodedCertificateChain)1329     native void nativeSslClientCert(int handle,
1330                                     int ctx,
1331                                     byte[][] asn1DerEncodedCertificateChain);
1332 
nativeSslClientCert(int handle, byte[] pkey, byte[][] asn1DerEncodedCertificateChain)1333     native void nativeSslClientCert(int handle,
1334                                     byte[] pkey,
1335                                     byte[][] asn1DerEncodedCertificateChain);
1336 
1337     /**
1338      * Returns true when the contents of the frame is an RTL or vertical-rl
1339      * page. This is used for determining whether a frame should be initially
1340      * scrolled right-most as opposed to left-most.
1341      * @return true when the frame should be initially scrolled right-most
1342      * based on the text direction and writing mode.
1343      */
getShouldStartScrolledRight()1344     /* package */ boolean getShouldStartScrolledRight() {
1345         return nativeGetShouldStartScrolledRight(mNativeFrame);
1346     }
1347 
nativeGetShouldStartScrolledRight(int nativeBrowserFrame)1348     private native boolean nativeGetShouldStartScrolledRight(int nativeBrowserFrame);
1349 }
1350