1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2  * vim: ts=4 sw=4 expandtab:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 package org.mozilla.gecko;
8 
9 import java.util.Set;
10 
11 import org.json.JSONException;
12 import org.json.JSONObject;
13 import org.mozilla.gecko.annotation.ReflectionTarget;
14 import org.mozilla.gecko.annotation.WrapForJNI;
15 import org.mozilla.gecko.gfx.LayerView;
16 import org.mozilla.gecko.mozglue.JNIObject;
17 import org.mozilla.gecko.util.EventCallback;
18 import org.mozilla.gecko.util.GeckoEventListener;
19 import org.mozilla.gecko.util.NativeEventListener;
20 import org.mozilla.gecko.util.NativeJSObject;
21 import org.mozilla.gecko.util.ThreadUtils;
22 
23 import android.app.Activity;
24 import android.content.Context;
25 import android.content.SharedPreferences;
26 import android.os.Binder;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.os.IBinder;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.util.AttributeSet;
33 import android.util.DisplayMetrics;
34 import android.util.Log;
35 import android.view.KeyEvent;
36 import android.view.View;
37 import android.view.inputmethod.EditorInfo;
38 import android.view.inputmethod.InputConnection;
39 
40 public class GeckoView extends LayerView
41     implements ContextGetter, GeckoEventListener, NativeEventListener {
42 
43     private static final String DEFAULT_SHARED_PREFERENCES_FILE = "GeckoView";
44     private static final String LOGTAG = "GeckoView";
45 
46     private ChromeDelegate mChromeDelegate;
47     private ContentDelegate mContentDelegate;
48 
49     private InputConnectionListener mInputConnectionListener;
50 
51     protected boolean onAttachedToWindowCalled;
52     protected String chromeURI = getGeckoInterface().getDefaultChromeURI();
53     protected int screenId = 0; // default to the primary screen
54 
55     @Override
handleMessage(final String event, final JSONObject message)56     public void handleMessage(final String event, final JSONObject message) {
57         ThreadUtils.postToUiThread(new Runnable() {
58             @Override
59             public void run() {
60                 try {
61                     if (event.equals("Gecko:Ready")) {
62                         handleReady(message);
63                     } else if (event.equals("Content:StateChange")) {
64                         handleStateChange(message);
65                     } else if (event.equals("Content:LoadError")) {
66                         handleLoadError(message);
67                     } else if (event.equals("Content:PageShow")) {
68                         handlePageShow(message);
69                     } else if (event.equals("DOMTitleChanged")) {
70                         handleTitleChanged(message);
71                     } else if (event.equals("Link:Favicon")) {
72                         handleLinkFavicon(message);
73                     } else if (event.equals("Prompt:Show") || event.equals("Prompt:ShowTop")) {
74                         handlePrompt(message);
75                     } else if (event.equals("Accessibility:Event")) {
76                         int mode = getImportantForAccessibility();
77                         if (mode == View.IMPORTANT_FOR_ACCESSIBILITY_YES ||
78                                 mode == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
79                             GeckoAccessibility.sendAccessibilityEvent(message);
80                         }
81                     }
82                 } catch (Exception e) {
83                     Log.e(LOGTAG, "handleMessage threw for " + event, e);
84                 }
85             }
86         });
87     }
88 
89     @Override
handleMessage(final String event, final NativeJSObject message, final EventCallback callback)90     public void handleMessage(final String event, final NativeJSObject message, final EventCallback callback) {
91         try {
92             if ("Accessibility:Ready".equals(event)) {
93                 GeckoAccessibility.updateAccessibilitySettings(getContext());
94             } else if ("GeckoView:Message".equals(event)) {
95                 // We need to pull out the bundle while on the Gecko thread.
96                 NativeJSObject json = message.optObject("data", null);
97                 if (json == null) {
98                     // Must have payload to call the message handler.
99                     return;
100                 }
101                 final Bundle data = json.toBundle();
102                 ThreadUtils.postToUiThread(new Runnable() {
103                     @Override
104                     public void run() {
105                         handleScriptMessage(data, callback);
106                     }
107                 });
108             }
109         } catch (Exception e) {
110             Log.w(LOGTAG, "handleMessage threw for " + event, e);
111         }
112     }
113 
114     @WrapForJNI(dispatchTo = "proxy")
115     protected static final class Window extends JNIObject {
116         @WrapForJNI(skip = true)
Window()117         /* package */ Window() {}
118 
open(Window instance, GeckoView view, Object compositor, String chromeURI, int screenId)119         static native void open(Window instance, GeckoView view, Object compositor,
120                                 String chromeURI, int screenId);
121 
disposeNative()122         @Override protected native void disposeNative();
close()123         native void close();
reattach(GeckoView view, Object compositor)124         native void reattach(GeckoView view, Object compositor);
loadUri(String uri, int flags)125         native void loadUri(String uri, int flags);
126     }
127 
128     // Object to hold onto our nsWindow connection when GeckoView gets destroyed.
129     private static class StateBinder extends Binder implements Parcelable {
130         public final Parcelable superState;
131         public final Window window;
132 
StateBinder(Parcelable superState, Window window)133         public StateBinder(Parcelable superState, Window window) {
134             this.superState = superState;
135             this.window = window;
136         }
137 
138         @Override
describeContents()139         public int describeContents() {
140             return 0;
141         }
142 
143         @Override
writeToParcel(Parcel out, int flags)144         public void writeToParcel(Parcel out, int flags) {
145             // Always write out the super-state, so that even if we lose this binder, we
146             // will still have something to pass into super.onRestoreInstanceState.
147             out.writeParcelable(superState, flags);
148             out.writeStrongBinder(this);
149         }
150 
151         @ReflectionTarget
152         public static final Parcelable.Creator<StateBinder> CREATOR
153             = new Parcelable.Creator<StateBinder>() {
154                 @Override
155                 public StateBinder createFromParcel(Parcel in) {
156                     final Parcelable superState = in.readParcelable(null);
157                     final IBinder binder = in.readStrongBinder();
158                     if (binder instanceof StateBinder) {
159                         return (StateBinder) binder;
160                     }
161                     // Not the original object we saved; return null state.
162                     return new StateBinder(superState, null);
163                 }
164 
165                 @Override
166                 public StateBinder[] newArray(int size) {
167                     return new StateBinder[size];
168                 }
169             };
170     }
171 
172     protected Window window;
173     private boolean stateSaved;
174 
GeckoView(Context context)175     public GeckoView(Context context) {
176         super(context);
177         init(context);
178     }
179 
GeckoView(Context context, AttributeSet attrs)180     public GeckoView(Context context, AttributeSet attrs) {
181         super(context, attrs);
182         init(context);
183     }
184 
init(Context context)185     private void init(Context context) {
186         if (GeckoAppShell.getApplicationContext() == null) {
187             GeckoAppShell.setApplicationContext(context.getApplicationContext());
188         }
189 
190         // Set the GeckoInterface if the context is an activity and the GeckoInterface
191         // has not already been set
192         if (context instanceof Activity && getGeckoInterface() == null) {
193             setGeckoInterface(new BaseGeckoInterface(context));
194             GeckoAppShell.setContextGetter(this);
195         }
196 
197         // Perform common initialization for Fennec/GeckoView.
198         GeckoAppShell.setLayerView(this);
199 
200         initializeView(EventDispatcher.getInstance());
201     }
202 
203     @Override
onSaveInstanceState()204     protected Parcelable onSaveInstanceState()
205     {
206         final Parcelable superState = super.onSaveInstanceState();
207         stateSaved = true;
208         return new StateBinder(superState, this.window);
209     }
210 
211     @Override
onRestoreInstanceState(final Parcelable state)212     protected void onRestoreInstanceState(final Parcelable state)
213     {
214         final StateBinder stateBinder = (StateBinder) state;
215 
216         if (stateBinder.window != null) {
217             this.window = stateBinder.window;
218         }
219         stateSaved = false;
220 
221         if (onAttachedToWindowCalled) {
222             reattachWindow();
223         }
224 
225         // We have to always call super.onRestoreInstanceState because View keeps
226         // track of these calls and throws an exception when we don't call it.
227         super.onRestoreInstanceState(stateBinder.superState);
228     }
229 
openWindow()230     protected void openWindow() {
231 
232         if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
233             Window.open(window, this, getCompositor(),
234                         chromeURI, screenId);
235         } else {
236             GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY, Window.class,
237                     "open", window, GeckoView.class, this, Object.class, getCompositor(),
238                     String.class, chromeURI, screenId);
239         }
240     }
241 
reattachWindow()242     protected void reattachWindow() {
243         if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
244             window.reattach(this, getCompositor());
245         } else {
246             GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
247                     window, "reattach", GeckoView.class, this, Object.class, getCompositor());
248         }
249     }
250 
251     @Override
onAttachedToWindow()252     public void onAttachedToWindow()
253     {
254         final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
255 
256         if (window == null) {
257             // Open a new nsWindow if we didn't have one from before.
258             window = new Window();
259             openWindow();
260         } else {
261             reattachWindow();
262         }
263 
264         super.onAttachedToWindow();
265 
266         onAttachedToWindowCalled = true;
267     }
268 
269     @Override
onDetachedFromWindow()270     public void onDetachedFromWindow()
271     {
272         super.onDetachedFromWindow();
273         super.destroy();
274 
275         if (stateSaved) {
276             // If we saved state earlier, we don't want to close the nsWindow.
277             return;
278         }
279 
280         if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
281             window.close();
282             window.disposeNative();
283         } else {
284             GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
285                     window, "close");
286             GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
287                     window, "disposeNative");
288         }
289 
290         onAttachedToWindowCalled = false;
291     }
292 
293     @WrapForJNI public static final int LOAD_DEFAULT = 0;
294     @WrapForJNI public static final int LOAD_NEW_TAB = 1;
295     @WrapForJNI public static final int LOAD_SWITCH_TAB = 2;
296 
loadUri(String uri, int flags)297     public void loadUri(String uri, int flags) {
298         if (window == null) {
299             throw new IllegalStateException("Not attached to window");
300         }
301 
302         if (GeckoThread.isRunning()) {
303             window.loadUri(uri, flags);
304         }  else {
305             GeckoThread.queueNativeCall(window, "loadUri", String.class, uri, flags);
306         }
307     }
308 
setInputConnectionListener(final InputConnectionListener icl)309     /* package */ void setInputConnectionListener(final InputConnectionListener icl) {
310         mInputConnectionListener = icl;
311     }
312 
313     @Override
getHandler()314     public Handler getHandler() {
315         if (mInputConnectionListener != null) {
316             return mInputConnectionListener.getHandler(super.getHandler());
317         }
318         return super.getHandler();
319     }
320 
321     @Override
onCreateInputConnection(EditorInfo outAttrs)322     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
323         if (mInputConnectionListener != null) {
324             return mInputConnectionListener.onCreateInputConnection(outAttrs);
325         }
326         return null;
327     }
328 
329     @Override
onKeyPreIme(int keyCode, KeyEvent event)330     public boolean onKeyPreIme(int keyCode, KeyEvent event) {
331         if (super.onKeyPreIme(keyCode, event)) {
332             return true;
333         }
334         return mInputConnectionListener != null &&
335                 mInputConnectionListener.onKeyPreIme(keyCode, event);
336     }
337 
338     @Override
onKeyUp(int keyCode, KeyEvent event)339     public boolean onKeyUp(int keyCode, KeyEvent event) {
340         if (super.onKeyUp(keyCode, event)) {
341             return true;
342         }
343         return mInputConnectionListener != null &&
344                 mInputConnectionListener.onKeyUp(keyCode, event);
345     }
346 
347     @Override
onKeyDown(int keyCode, KeyEvent event)348     public boolean onKeyDown(int keyCode, KeyEvent event) {
349         if (super.onKeyDown(keyCode, event)) {
350             return true;
351         }
352         return mInputConnectionListener != null &&
353                 mInputConnectionListener.onKeyDown(keyCode, event);
354     }
355 
356     @Override
onKeyLongPress(int keyCode, KeyEvent event)357     public boolean onKeyLongPress(int keyCode, KeyEvent event) {
358         if (super.onKeyLongPress(keyCode, event)) {
359             return true;
360         }
361         return mInputConnectionListener != null &&
362                 mInputConnectionListener.onKeyLongPress(keyCode, event);
363     }
364 
365     @Override
onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)366     public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
367         if (super.onKeyMultiple(keyCode, repeatCount, event)) {
368             return true;
369         }
370         return mInputConnectionListener != null &&
371                 mInputConnectionListener.onKeyMultiple(keyCode, repeatCount, event);
372     }
373 
isIMEEnabled()374     /* package */ boolean isIMEEnabled() {
375         return mInputConnectionListener != null &&
376                 mInputConnectionListener.isIMEEnabled();
377     }
378 
importScript(final String url)379     public void importScript(final String url) {
380         if (url.startsWith("resource://android/assets/")) {
381             GeckoAppShell.notifyObservers("GeckoView:ImportScript", url);
382             return;
383         }
384 
385         throw new IllegalArgumentException("Must import script from 'resources://android/assets/' location.");
386     }
387 
handleReady(final JSONObject message)388     private void handleReady(final JSONObject message) {
389         if (mChromeDelegate != null) {
390             mChromeDelegate.onReady(this);
391         }
392     }
393 
handleStateChange(final JSONObject message)394     private void handleStateChange(final JSONObject message) throws JSONException {
395         int state = message.getInt("state");
396         if ((state & GeckoAppShell.WPL_STATE_IS_NETWORK) != 0) {
397             if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
398                 if (mContentDelegate != null) {
399                     int id = message.getInt("tabID");
400                     mContentDelegate.onPageStart(this, new Browser(id), message.getString("uri"));
401                 }
402             } else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
403                 if (mContentDelegate != null) {
404                     int id = message.getInt("tabID");
405                     mContentDelegate.onPageStop(this, new Browser(id), message.getBoolean("success"));
406                 }
407             }
408         }
409     }
410 
handleLoadError(final JSONObject message)411     private void handleLoadError(final JSONObject message) throws JSONException {
412         if (mContentDelegate != null) {
413             int id = message.getInt("tabID");
414             mContentDelegate.onPageStop(GeckoView.this, new Browser(id), false);
415         }
416     }
417 
handlePageShow(final JSONObject message)418     private void handlePageShow(final JSONObject message) throws JSONException {
419         if (mContentDelegate != null) {
420             int id = message.getInt("tabID");
421             mContentDelegate.onPageShow(GeckoView.this, new Browser(id));
422         }
423     }
424 
handleTitleChanged(final JSONObject message)425     private void handleTitleChanged(final JSONObject message) throws JSONException {
426         if (mContentDelegate != null) {
427             int id = message.getInt("tabID");
428             mContentDelegate.onReceivedTitle(GeckoView.this, new Browser(id), message.getString("title"));
429         }
430     }
431 
handleLinkFavicon(final JSONObject message)432     private void handleLinkFavicon(final JSONObject message) throws JSONException {
433         if (mContentDelegate != null) {
434             int id = message.getInt("tabID");
435             mContentDelegate.onReceivedFavicon(GeckoView.this, new Browser(id), message.getString("href"), message.getInt("size"));
436         }
437     }
438 
handlePrompt(final JSONObject message)439     private void handlePrompt(final JSONObject message) throws JSONException {
440         if (mChromeDelegate != null) {
441             String hint = message.optString("hint");
442             if ("alert".equals(hint)) {
443                 String text = message.optString("text");
444                 mChromeDelegate.onAlert(GeckoView.this, null, text, new PromptResult(message));
445             } else if ("confirm".equals(hint)) {
446                 String text = message.optString("text");
447                 mChromeDelegate.onConfirm(GeckoView.this, null, text, new PromptResult(message));
448             } else if ("prompt".equals(hint)) {
449                 String text = message.optString("text");
450                 String defaultValue = message.optString("textbox0");
451                 mChromeDelegate.onPrompt(GeckoView.this, null, text, defaultValue, new PromptResult(message));
452             } else if ("remotedebug".equals(hint)) {
453                 mChromeDelegate.onDebugRequest(GeckoView.this, new PromptResult(message));
454             }
455         }
456     }
457 
handleScriptMessage(final Bundle data, final EventCallback callback)458     private void handleScriptMessage(final Bundle data, final EventCallback callback) {
459         if (mChromeDelegate != null) {
460             MessageResult result = null;
461             if (callback != null) {
462                 result = new MessageResult(callback);
463             }
464             mChromeDelegate.onScriptMessage(GeckoView.this, data, result);
465         }
466     }
467 
468     /**
469     * Set the chrome callback handler.
470     * This will replace the current handler.
471     * @param chrome An implementation of GeckoViewChrome.
472     */
setChromeDelegate(ChromeDelegate chrome)473     public void setChromeDelegate(ChromeDelegate chrome) {
474         mChromeDelegate = chrome;
475     }
476 
477     /**
478     * Set the content callback handler.
479     * This will replace the current handler.
480     * @param content An implementation of ContentDelegate.
481     */
setContentDelegate(ContentDelegate content)482     public void setContentDelegate(ContentDelegate content) {
483         mContentDelegate = content;
484     }
485 
setGeckoInterface(final BaseGeckoInterface geckoInterface)486     public static void setGeckoInterface(final BaseGeckoInterface geckoInterface) {
487         GeckoAppShell.setGeckoInterface(geckoInterface);
488     }
489 
getGeckoInterface()490     public static GeckoAppShell.GeckoInterface getGeckoInterface() {
491         return GeckoAppShell.getGeckoInterface();
492     }
493 
getSharedPreferencesFile()494     protected String getSharedPreferencesFile() {
495         return DEFAULT_SHARED_PREFERENCES_FILE;
496     }
497 
498     @Override
getSharedPreferences()499     public SharedPreferences getSharedPreferences() {
500         return getContext().getSharedPreferences(getSharedPreferencesFile(), 0);
501     }
502 
503     /**
504     * Wrapper for a browser in the GeckoView container. Associated with a browser
505     * element in the Gecko system.
506     */
507     public class Browser {
508         private final int mId;
Browser(int Id)509         private Browser(int Id) {
510             mId = Id;
511         }
512 
513         /**
514         * Get the ID of the Browser. This is the same ID used by Gecko for it's underlying
515         * browser element.
516         * @return The integer ID of the Browser.
517         */
getId()518         private int getId() {
519             return mId;
520         }
521 
522         /**
523         * Load a URL resource into the Browser.
524         * @param url The URL string.
525         */
loadUrl(String url)526         public void loadUrl(String url) {
527             JSONObject args = new JSONObject();
528             try {
529                 args.put("url", url);
530                 args.put("parentId", -1);
531                 args.put("newTab", false);
532                 args.put("tabID", mId);
533             } catch (Exception e) {
534                 Log.w(LOGTAG, "Error building JSON arguments for loadUrl.", e);
535             }
536             GeckoAppShell.notifyObservers("Tab:Load", args.toString());
537         }
538     }
539 
540     /* Provides a means for the client to indicate whether a JavaScript
541      * dialog request should proceed. An instance of this class is passed to
542      * various GeckoViewChrome callback actions.
543      */
544     public class PromptResult {
545         private final int RESULT_OK = 0;
546         private final int RESULT_CANCEL = 1;
547 
548         private final JSONObject mMessage;
549 
PromptResult(JSONObject message)550         public PromptResult(JSONObject message) {
551             mMessage = message;
552         }
553 
makeResult(int resultCode)554         private JSONObject makeResult(int resultCode) {
555             JSONObject result = new JSONObject();
556             try {
557                 result.put("button", resultCode);
558             } catch (JSONException ex) { }
559             return result;
560         }
561 
562         /**
563         * Handle a confirmation response from the user.
564         */
confirm()565         public void confirm() {
566             JSONObject result = makeResult(RESULT_OK);
567             EventDispatcher.sendResponse(mMessage, result);
568         }
569 
570         /**
571         * Handle a confirmation response from the user.
572         * @param value String value to return to the browser context.
573         */
confirmWithValue(String value)574         public void confirmWithValue(String value) {
575             JSONObject result = makeResult(RESULT_OK);
576             try {
577                 result.put("textbox0", value);
578             } catch (JSONException ex) { }
579             EventDispatcher.sendResponse(mMessage, result);
580         }
581 
582         /**
583         * Handle a cancellation response from the user.
584         */
cancel()585         public void cancel() {
586             JSONObject result = makeResult(RESULT_CANCEL);
587             EventDispatcher.sendResponse(mMessage, result);
588         }
589     }
590 
591     /* Provides a means for the client to respond to a script message with some data.
592      * An instance of this class is passed to GeckoViewChrome.onScriptMessage.
593      */
594     public class MessageResult {
595         private final EventCallback mCallback;
596 
MessageResult(EventCallback callback)597         public MessageResult(EventCallback callback) {
598             if (callback == null) {
599                 throw new IllegalArgumentException("EventCallback should not be null.");
600             }
601             mCallback = callback;
602         }
603 
bundleToJSON(Bundle data)604         private JSONObject bundleToJSON(Bundle data) {
605             JSONObject result = new JSONObject();
606             if (data == null) {
607                 return result;
608             }
609 
610             final Set<String> keys = data.keySet();
611             for (String key : keys) {
612                 try {
613                     result.put(key, data.get(key));
614                 } catch (JSONException e) {
615                 }
616             }
617             return result;
618         }
619 
620         /**
621         * Handle a successful response to a script message.
622         * @param value Bundle value to return to the script context.
623         */
success(Bundle data)624         public void success(Bundle data) {
625             mCallback.sendSuccess(bundleToJSON(data));
626         }
627 
628         /**
629         * Handle a failure response to a script message.
630         */
failure(Bundle data)631         public void failure(Bundle data) {
632             mCallback.sendError(bundleToJSON(data));
633         }
634     }
635 
636     public interface ChromeDelegate {
637         /**
638         * Tell the host application that Gecko is ready to handle requests.
639         * @param view The GeckoView that initiated the callback.
640         */
onReady(GeckoView view)641         public void onReady(GeckoView view);
642 
643         /**
644         * Tell the host application to display an alert dialog.
645         * @param view The GeckoView that initiated the callback.
646         * @param browser The Browser that is loading the content.
647         * @param message The string to display in the dialog.
648         * @param result A PromptResult used to send back the result without blocking.
649         * Defaults to cancel requests.
650         */
onAlert(GeckoView view, GeckoView.Browser browser, String message, GeckoView.PromptResult result)651         public void onAlert(GeckoView view, GeckoView.Browser browser, String message, GeckoView.PromptResult result);
652 
653         /**
654         * Tell the host application to display a confirmation dialog.
655         * @param view The GeckoView that initiated the callback.
656         * @param browser The Browser that is loading the content.
657         * @param message The string to display in the dialog.
658         * @param result A PromptResult used to send back the result without blocking.
659         * Defaults to cancel requests.
660         */
onConfirm(GeckoView view, GeckoView.Browser browser, String message, GeckoView.PromptResult result)661         public void onConfirm(GeckoView view, GeckoView.Browser browser, String message, GeckoView.PromptResult result);
662 
663         /**
664         * Tell the host application to display an input prompt dialog.
665         * @param view The GeckoView that initiated the callback.
666         * @param browser The Browser that is loading the content.
667         * @param message The string to display in the dialog.
668         * @param defaultValue The string to use as default input.
669         * @param result A PromptResult used to send back the result without blocking.
670         * Defaults to cancel requests.
671         */
onPrompt(GeckoView view, GeckoView.Browser browser, String message, String defaultValue, GeckoView.PromptResult result)672         public void onPrompt(GeckoView view, GeckoView.Browser browser, String message, String defaultValue, GeckoView.PromptResult result);
673 
674         /**
675         * Tell the host application to display a remote debugging request dialog.
676         * @param view The GeckoView that initiated the callback.
677         * @param result A PromptResult used to send back the result without blocking.
678         * Defaults to cancel requests.
679         */
onDebugRequest(GeckoView view, GeckoView.PromptResult result)680         public void onDebugRequest(GeckoView view, GeckoView.PromptResult result);
681 
682         /**
683         * Receive a message from an imported script.
684         * @param view The GeckoView that initiated the callback.
685         * @param data Bundle of data sent with the message. Never null.
686         * @param result A MessageResult used to send back a response without blocking. Can be null.
687         * Defaults to do nothing.
688         */
onScriptMessage(GeckoView view, Bundle data, GeckoView.MessageResult result)689         public void onScriptMessage(GeckoView view, Bundle data, GeckoView.MessageResult result);
690     }
691 
692     public interface ContentDelegate {
693         /**
694         * A Browser has started loading content from the network.
695         * @param view The GeckoView that initiated the callback.
696         * @param browser The Browser that is loading the content.
697         * @param url The resource being loaded.
698         */
onPageStart(GeckoView view, GeckoView.Browser browser, String url)699         public void onPageStart(GeckoView view, GeckoView.Browser browser, String url);
700 
701         /**
702         * A Browser has finished loading content from the network.
703         * @param view The GeckoView that initiated the callback.
704         * @param browser The Browser that was loading the content.
705         * @param success Whether the page loaded successfully or an error occurred.
706         */
onPageStop(GeckoView view, GeckoView.Browser browser, boolean success)707         public void onPageStop(GeckoView view, GeckoView.Browser browser, boolean success);
708 
709         /**
710         * A Browser is displaying content. This page could have been loaded via
711         * network or from the session history.
712         * @param view The GeckoView that initiated the callback.
713         * @param browser The Browser that is showing the content.
714         */
onPageShow(GeckoView view, GeckoView.Browser browser)715         public void onPageShow(GeckoView view, GeckoView.Browser browser);
716 
717         /**
718         * A page title was discovered in the content or updated after the content
719         * loaded.
720         * @param view The GeckoView that initiated the callback.
721         * @param browser The Browser that is showing the content.
722         * @param title The title sent from the content.
723         */
onReceivedTitle(GeckoView view, GeckoView.Browser browser, String title)724         public void onReceivedTitle(GeckoView view, GeckoView.Browser browser, String title);
725 
726         /**
727         * A link element was discovered in the content or updated after the content
728         * loaded that specifies a favicon.
729         * @param view The GeckoView that initiated the callback.
730         * @param browser The Browser that is showing the content.
731         * @param url The href of the link element specifying the favicon.
732         * @param size The maximum size specified for the favicon, or -1 for any size.
733         */
onReceivedFavicon(GeckoView view, GeckoView.Browser browser, String url, int size)734         public void onReceivedFavicon(GeckoView view, GeckoView.Browser browser, String url, int size);
735     }
736 }
737