2013-05-29 21:31:43 -07:00
|
|
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
package org.mozilla.gecko;
|
|
|
|
|
|
|
|
import org.mozilla.gecko.db.BrowserDB;
|
|
|
|
import org.mozilla.gecko.gfx.LayerView;
|
2013-08-23 11:46:05 -07:00
|
|
|
import org.mozilla.gecko.mozglue.GeckoLoader;
|
|
|
|
import org.mozilla.gecko.util.Clipboard;
|
2013-09-04 21:33:11 -07:00
|
|
|
import org.mozilla.gecko.util.HardwareUtils;
|
2013-05-29 21:31:43 -07:00
|
|
|
import org.mozilla.gecko.util.GeckoEventListener;
|
|
|
|
import org.mozilla.gecko.util.ThreadUtils;
|
2014-08-20 17:37:36 -07:00
|
|
|
import org.mozilla.gecko.util.EventCallback;
|
|
|
|
import org.mozilla.gecko.util.NativeEventListener;
|
|
|
|
import org.mozilla.gecko.util.NativeJSObject;
|
2013-05-29 21:31:43 -07:00
|
|
|
|
2013-11-06 14:59:07 -08:00
|
|
|
import org.json.JSONException;
|
2013-05-29 21:31:43 -07:00
|
|
|
import org.json.JSONObject;
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
2013-12-03 15:05:43 -08:00
|
|
|
import android.content.SharedPreferences;
|
2013-05-29 21:31:43 -07:00
|
|
|
import android.content.res.TypedArray;
|
2014-10-14 21:33:14 -07:00
|
|
|
import android.os.Bundle;
|
2013-08-23 11:46:05 -07:00
|
|
|
import android.os.Handler;
|
2013-05-29 21:31:43 -07:00
|
|
|
import android.util.AttributeSet;
|
|
|
|
import android.util.Log;
|
2014-08-27 08:15:00 -07:00
|
|
|
import android.view.View;
|
2014-08-14 12:52:51 -07:00
|
|
|
|
2013-11-06 14:56:23 -08:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
2014-10-14 21:33:14 -07:00
|
|
|
import java.util.Set;
|
2013-11-06 14:56:23 -08:00
|
|
|
|
2013-05-29 21:31:43 -07:00
|
|
|
public class GeckoView extends LayerView
|
2014-08-14 12:52:51 -07:00
|
|
|
implements ContextGetter {
|
2013-05-29 21:31:43 -07:00
|
|
|
|
2013-12-03 15:05:43 -08:00
|
|
|
private static final String DEFAULT_SHARED_PREFERENCES_FILE = "GeckoView";
|
2013-08-23 11:46:05 -07:00
|
|
|
private static final String LOGTAG = "GeckoView";
|
|
|
|
|
2013-11-06 14:58:29 -08:00
|
|
|
private ChromeDelegate mChromeDelegate;
|
2013-11-06 14:59:07 -08:00
|
|
|
private ContentDelegate mContentDelegate;
|
2013-11-06 14:58:29 -08:00
|
|
|
|
2014-08-20 17:37:36 -07:00
|
|
|
private final GeckoEventListener mGeckoEventListener = new GeckoEventListener() {
|
2014-08-14 12:52:51 -07:00
|
|
|
@Override
|
|
|
|
public void handleMessage(final String event, final JSONObject message) {
|
|
|
|
ThreadUtils.postToUiThread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
try {
|
|
|
|
if (event.equals("Gecko:Ready")) {
|
|
|
|
handleReady(message);
|
|
|
|
} else if (event.equals("Content:StateChange")) {
|
|
|
|
handleStateChange(message);
|
|
|
|
} else if (event.equals("Content:LoadError")) {
|
|
|
|
handleLoadError(message);
|
|
|
|
} else if (event.equals("Content:PageShow")) {
|
|
|
|
handlePageShow(message);
|
|
|
|
} else if (event.equals("DOMTitleChanged")) {
|
|
|
|
handleTitleChanged(message);
|
|
|
|
} else if (event.equals("Link:Favicon")) {
|
|
|
|
handleLinkFavicon(message);
|
|
|
|
} else if (event.equals("Prompt:Show") || event.equals("Prompt:ShowTop")) {
|
|
|
|
handlePrompt(message);
|
2014-08-20 17:37:36 -07:00
|
|
|
} else if (event.equals("Accessibility:Event")) {
|
2014-08-27 08:15:00 -07:00
|
|
|
int mode = getImportantForAccessibility();
|
|
|
|
if (mode == View.IMPORTANT_FOR_ACCESSIBILITY_YES ||
|
|
|
|
mode == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
|
|
|
|
GeckoAccessibility.sendAccessibilityEvent(message);
|
|
|
|
}
|
2014-08-14 12:52:51 -07:00
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.e(LOGTAG, "handleMessage threw for " + event, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-08-20 17:37:36 -07:00
|
|
|
private final NativeEventListener mNativeEventListener = new NativeEventListener() {
|
|
|
|
@Override
|
|
|
|
public void handleMessage(final String event, final NativeJSObject message, final EventCallback callback) {
|
2014-10-14 21:33:14 -07:00
|
|
|
try {
|
|
|
|
if ("Accessibility:Ready".equals(event)) {
|
|
|
|
GeckoAccessibility.updateAccessibilitySettings(getContext());
|
|
|
|
} else if ("GeckoView:Message".equals(event)) {
|
|
|
|
// We need to pull out the bundle while on the Gecko thread.
|
|
|
|
NativeJSObject json = message.optObject("data", null);
|
|
|
|
if (json == null) {
|
|
|
|
// Must have payload to call the message handler.
|
|
|
|
return;
|
2014-08-20 17:37:36 -07:00
|
|
|
}
|
2014-10-14 21:33:14 -07:00
|
|
|
final Bundle data = json.toBundle();
|
|
|
|
ThreadUtils.postToUiThread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
handleScriptMessage(data, callback);
|
|
|
|
}
|
|
|
|
});
|
2014-08-20 17:37:36 -07:00
|
|
|
}
|
2014-10-14 21:33:14 -07:00
|
|
|
} catch (Exception e) {
|
|
|
|
Log.w(LOGTAG, "handleMessage threw for " + event, e);
|
|
|
|
}
|
2014-08-20 17:37:36 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-11-27 14:58:41 -08:00
|
|
|
public GeckoView(Context context) {
|
|
|
|
super(context);
|
|
|
|
init(context, null, true);
|
|
|
|
}
|
|
|
|
|
2013-05-29 21:31:43 -07:00
|
|
|
public GeckoView(Context context, AttributeSet attrs) {
|
|
|
|
super(context, attrs);
|
|
|
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GeckoView);
|
|
|
|
String url = a.getString(R.styleable.GeckoView_url);
|
2013-08-02 13:46:07 -07:00
|
|
|
boolean doInit = a.getBoolean(R.styleable.GeckoView_doinit, true);
|
2013-05-29 21:31:43 -07:00
|
|
|
a.recycle();
|
2013-11-27 14:58:41 -08:00
|
|
|
init(context, url, doInit);
|
|
|
|
}
|
2013-05-29 21:31:43 -07:00
|
|
|
|
2013-11-27 14:58:41 -08:00
|
|
|
private void init(Context context, String url, boolean doInit) {
|
2013-11-07 11:38:00 -08:00
|
|
|
// TODO: Fennec currently takes care of its own initialization, so this
|
|
|
|
// flag is a hack used in Fennec to prevent GeckoView initialization.
|
|
|
|
// This should go away once Fennec also uses GeckoView for
|
|
|
|
// initialization.
|
2013-08-02 13:46:07 -07:00
|
|
|
if (!doInit)
|
|
|
|
return;
|
|
|
|
|
2013-08-20 14:54:16 -07:00
|
|
|
// If running outside of a GeckoActivity (eg, from a library project),
|
|
|
|
// load the native code and disable content providers
|
2013-10-23 09:33:56 -07:00
|
|
|
boolean isGeckoActivity = false;
|
|
|
|
try {
|
|
|
|
isGeckoActivity = context instanceof GeckoActivity;
|
|
|
|
} catch (NoClassDefFoundError ex) {}
|
|
|
|
|
|
|
|
if (!isGeckoActivity) {
|
2013-08-23 11:46:05 -07:00
|
|
|
// Set the GeckoInterface if the context is an activity and the GeckoInterface
|
|
|
|
// has not already been set
|
|
|
|
if (context instanceof Activity && getGeckoInterface() == null) {
|
|
|
|
setGeckoInterface(new BaseGeckoInterface(context));
|
|
|
|
}
|
|
|
|
|
|
|
|
Clipboard.init(context);
|
2013-09-04 21:33:11 -07:00
|
|
|
HardwareUtils.init(context);
|
2014-02-27 12:32:34 -08:00
|
|
|
|
|
|
|
// If you want to use GeckoNetworkManager, start it.
|
2013-09-04 21:33:11 -07:00
|
|
|
|
2014-07-24 09:39:48 -07:00
|
|
|
GeckoLoader.loadMozGlue(context);
|
2013-08-20 14:54:16 -07:00
|
|
|
BrowserDB.setEnableContentProviders(false);
|
2013-10-23 09:33:56 -07:00
|
|
|
}
|
2013-08-20 14:54:16 -07:00
|
|
|
|
2013-08-08 06:02:02 -07:00
|
|
|
if (url != null) {
|
|
|
|
GeckoThread.setUri(url);
|
|
|
|
GeckoThread.setAction(Intent.ACTION_VIEW);
|
2013-05-29 21:31:43 -07:00
|
|
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(url));
|
|
|
|
}
|
|
|
|
GeckoAppShell.setContextGetter(this);
|
|
|
|
if (context instanceof Activity) {
|
|
|
|
Tabs tabs = Tabs.getInstance();
|
2013-07-15 12:12:15 -07:00
|
|
|
tabs.attachToContext(context);
|
2013-05-29 21:31:43 -07:00
|
|
|
}
|
2013-11-06 14:59:07 -08:00
|
|
|
|
2014-08-20 17:37:36 -07:00
|
|
|
EventDispatcher.getInstance().registerGeckoThreadListener(mGeckoEventListener,
|
2014-05-02 11:34:40 -07:00
|
|
|
"Gecko:Ready",
|
2014-08-20 17:37:36 -07:00
|
|
|
"Accessibility:Event",
|
2014-05-02 11:34:40 -07:00
|
|
|
"Content:StateChange",
|
|
|
|
"Content:LoadError",
|
|
|
|
"Content:PageShow",
|
|
|
|
"DOMTitleChanged",
|
|
|
|
"Link:Favicon",
|
|
|
|
"Prompt:Show",
|
|
|
|
"Prompt:ShowTop");
|
2013-05-29 21:31:43 -07:00
|
|
|
|
2014-08-20 17:37:36 -07:00
|
|
|
EventDispatcher.getInstance().registerGeckoThreadListener(mNativeEventListener,
|
2014-10-14 21:33:14 -07:00
|
|
|
"Accessibility:Ready",
|
|
|
|
"GeckoView:Message");
|
2014-08-20 17:37:36 -07:00
|
|
|
|
2014-05-02 11:34:40 -07:00
|
|
|
initializeView(EventDispatcher.getInstance());
|
2013-08-02 13:46:07 -07:00
|
|
|
|
2013-05-29 21:31:43 -07:00
|
|
|
if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {
|
2013-11-07 11:38:00 -08:00
|
|
|
// This is the first launch, so finish initialization and go.
|
|
|
|
GeckoProfile profile = GeckoProfile.get(context).forceCreate();
|
|
|
|
BrowserDB.initialize(profile.getName());
|
|
|
|
|
2013-05-29 21:31:43 -07:00
|
|
|
GeckoAppShell.setLayerView(this);
|
2014-09-30 15:20:58 -07:00
|
|
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent(
|
|
|
|
GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, getLayerClientObject()));
|
2013-08-08 06:02:02 -07:00
|
|
|
GeckoThread.createAndStart();
|
2013-11-07 11:38:00 -08:00
|
|
|
} else if(GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
|
|
|
|
// If Gecko is already running, that means the Activity was
|
|
|
|
// destroyed, so we need to re-attach Gecko to this GeckoView.
|
|
|
|
connectToGecko();
|
2013-05-29 21:31:43 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-06 14:56:23 -08:00
|
|
|
/**
|
|
|
|
* Add a Browser to the GeckoView container.
|
|
|
|
* @param url The URL resource to load into the new Browser.
|
|
|
|
*/
|
|
|
|
public Browser addBrowser(String url) {
|
|
|
|
Tab tab = Tabs.getInstance().loadUrl(url, Tabs.LOADURL_NEW_TAB);
|
|
|
|
if (tab != null) {
|
|
|
|
return new Browser(tab.getId());
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a Browser from the GeckoView container.
|
|
|
|
* @param browser The Browser to remove.
|
|
|
|
*/
|
|
|
|
public void removeBrowser(Browser browser) {
|
|
|
|
Tab tab = Tabs.getInstance().getTab(browser.getId());
|
|
|
|
if (tab != null) {
|
|
|
|
Tabs.getInstance().closeTab(tab);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the active/visible Browser.
|
|
|
|
* @param browser The Browser to make selected.
|
|
|
|
*/
|
|
|
|
public void setCurrentBrowser(Browser browser) {
|
|
|
|
Tab tab = Tabs.getInstance().getTab(browser.getId());
|
|
|
|
if (tab != null) {
|
|
|
|
Tabs.getInstance().selectTab(tab.getId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the active/visible Browser.
|
|
|
|
* @return The current selected Browser.
|
|
|
|
*/
|
|
|
|
public Browser getCurrentBrowser() {
|
|
|
|
Tab tab = Tabs.getInstance().getSelectedTab();
|
|
|
|
if (tab != null) {
|
|
|
|
return new Browser(tab.getId());
|
|
|
|
}
|
|
|
|
return null;
|
2013-05-29 21:31:43 -07:00
|
|
|
}
|
|
|
|
|
2013-11-06 14:56:23 -08:00
|
|
|
/**
|
|
|
|
* Get the list of current Browsers in the GeckoView container.
|
|
|
|
* @return An unmodifiable List of Browser objects.
|
|
|
|
*/
|
|
|
|
public List<Browser> getBrowsers() {
|
|
|
|
ArrayList<Browser> browsers = new ArrayList<Browser>();
|
|
|
|
Iterable<Tab> tabs = Tabs.getInstance().getTabsInOrder();
|
|
|
|
for (Tab tab : tabs) {
|
|
|
|
browsers.add(new Browser(tab.getId()));
|
|
|
|
}
|
|
|
|
return Collections.unmodifiableList(browsers);
|
|
|
|
}
|
2013-08-13 13:43:00 -07:00
|
|
|
|
2014-10-14 21:32:15 -07:00
|
|
|
public void importScript(final String url) {
|
|
|
|
if (url.startsWith("resource://android/assets/")) {
|
|
|
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("GeckoView:ImportScript", url));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new IllegalArgumentException("Must import script from 'resources://android/assets/' location.");
|
|
|
|
}
|
|
|
|
|
2013-11-07 11:38:00 -08:00
|
|
|
private void connectToGecko() {
|
2013-11-06 14:58:29 -08:00
|
|
|
GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoRunning);
|
|
|
|
Tab selectedTab = Tabs.getInstance().getSelectedTab();
|
|
|
|
if (selectedTab != null)
|
|
|
|
Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
|
|
|
|
geckoConnected();
|
|
|
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
|
2013-11-07 11:38:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
private void handleReady(final JSONObject message) {
|
|
|
|
connectToGecko();
|
2013-11-06 14:58:29 -08:00
|
|
|
|
|
|
|
if (mChromeDelegate != null) {
|
|
|
|
mChromeDelegate.onReady(this);
|
2013-05-29 21:31:43 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-06 14:59:07 -08:00
|
|
|
private void handleStateChange(final JSONObject message) throws JSONException {
|
|
|
|
int state = message.getInt("state");
|
|
|
|
if ((state & GeckoAppShell.WPL_STATE_IS_NETWORK) != 0) {
|
|
|
|
if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
|
|
|
|
if (mContentDelegate != null) {
|
|
|
|
int id = message.getInt("tabID");
|
|
|
|
mContentDelegate.onPageStart(this, new Browser(id), message.getString("uri"));
|
|
|
|
}
|
|
|
|
} else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
|
|
|
|
if (mContentDelegate != null) {
|
|
|
|
int id = message.getInt("tabID");
|
|
|
|
mContentDelegate.onPageStop(this, new Browser(id), message.getBoolean("success"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleLoadError(final JSONObject message) throws JSONException {
|
|
|
|
if (mContentDelegate != null) {
|
|
|
|
int id = message.getInt("tabID");
|
|
|
|
mContentDelegate.onPageStop(GeckoView.this, new Browser(id), false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handlePageShow(final JSONObject message) throws JSONException {
|
|
|
|
if (mContentDelegate != null) {
|
|
|
|
int id = message.getInt("tabID");
|
|
|
|
mContentDelegate.onPageShow(GeckoView.this, new Browser(id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleTitleChanged(final JSONObject message) throws JSONException {
|
|
|
|
if (mContentDelegate != null) {
|
|
|
|
int id = message.getInt("tabID");
|
|
|
|
mContentDelegate.onReceivedTitle(GeckoView.this, new Browser(id), message.getString("title"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleLinkFavicon(final JSONObject message) throws JSONException {
|
|
|
|
if (mContentDelegate != null) {
|
|
|
|
int id = message.getInt("tabID");
|
|
|
|
mContentDelegate.onReceivedFavicon(GeckoView.this, new Browser(id), message.getString("href"), message.getInt("size"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-06 14:59:11 -08:00
|
|
|
private void handlePrompt(final JSONObject message) throws JSONException {
|
|
|
|
if (mChromeDelegate != null) {
|
|
|
|
String hint = message.optString("hint");
|
|
|
|
if ("alert".equals(hint)) {
|
|
|
|
String text = message.optString("text");
|
2014-07-07 13:28:03 -07:00
|
|
|
mChromeDelegate.onAlert(GeckoView.this, null, text, new PromptResult(message));
|
2013-11-06 14:59:11 -08:00
|
|
|
} else if ("confirm".equals(hint)) {
|
|
|
|
String text = message.optString("text");
|
2014-07-07 13:28:03 -07:00
|
|
|
mChromeDelegate.onConfirm(GeckoView.this, null, text, new PromptResult(message));
|
2013-11-06 14:59:11 -08:00
|
|
|
} else if ("prompt".equals(hint)) {
|
|
|
|
String text = message.optString("text");
|
|
|
|
String defaultValue = message.optString("textbox0");
|
2014-07-07 13:28:03 -07:00
|
|
|
mChromeDelegate.onPrompt(GeckoView.this, null, text, defaultValue, new PromptResult(message));
|
2013-11-06 14:59:11 -08:00
|
|
|
} else if ("remotedebug".equals(hint)) {
|
2014-07-07 13:28:03 -07:00
|
|
|
mChromeDelegate.onDebugRequest(GeckoView.this, new PromptResult(message));
|
2013-11-06 14:59:11 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-14 21:33:14 -07:00
|
|
|
private void handleScriptMessage(final Bundle data, final EventCallback callback) {
|
|
|
|
if (mChromeDelegate != null) {
|
|
|
|
MessageResult result = null;
|
|
|
|
if (callback != null) {
|
|
|
|
result = new MessageResult(callback);
|
|
|
|
}
|
|
|
|
mChromeDelegate.onScriptMessage(GeckoView.this, data, result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-06 14:58:29 -08:00
|
|
|
/**
|
|
|
|
* Set the chrome callback handler.
|
|
|
|
* This will replace the current handler.
|
|
|
|
* @param chrome An implementation of GeckoViewChrome.
|
|
|
|
*/
|
|
|
|
public void setChromeDelegate(ChromeDelegate chrome) {
|
|
|
|
mChromeDelegate = chrome;
|
|
|
|
}
|
|
|
|
|
2013-11-06 14:59:07 -08:00
|
|
|
/**
|
|
|
|
* Set the content callback handler.
|
|
|
|
* This will replace the current handler.
|
|
|
|
* @param content An implementation of ContentDelegate.
|
|
|
|
*/
|
|
|
|
public void setContentDelegate(ContentDelegate content) {
|
|
|
|
mContentDelegate = content;
|
|
|
|
}
|
|
|
|
|
2013-08-23 11:46:05 -07:00
|
|
|
public static void setGeckoInterface(final BaseGeckoInterface geckoInterface) {
|
|
|
|
GeckoAppShell.setGeckoInterface(geckoInterface);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static GeckoAppShell.GeckoInterface getGeckoInterface() {
|
|
|
|
return GeckoAppShell.getGeckoInterface();
|
2013-05-29 21:31:43 -07:00
|
|
|
}
|
2013-11-06 14:56:23 -08:00
|
|
|
|
2013-12-03 15:05:43 -08:00
|
|
|
protected String getSharedPreferencesFile() {
|
|
|
|
return DEFAULT_SHARED_PREFERENCES_FILE;
|
|
|
|
}
|
|
|
|
|
2014-10-10 15:58:19 -07:00
|
|
|
@Override
|
2013-12-03 15:05:43 -08:00
|
|
|
public SharedPreferences getSharedPreferences() {
|
|
|
|
return getContext().getSharedPreferences(getSharedPreferencesFile(), 0);
|
|
|
|
}
|
|
|
|
|
2013-11-06 14:56:23 -08:00
|
|
|
/**
|
|
|
|
* Wrapper for a browser in the GeckoView container. Associated with a browser
|
|
|
|
* element in the Gecko system.
|
|
|
|
*/
|
|
|
|
public class Browser {
|
|
|
|
private final int mId;
|
|
|
|
private Browser(int Id) {
|
|
|
|
mId = Id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the ID of the Browser. This is the same ID used by Gecko for it's underlying
|
|
|
|
* browser element.
|
|
|
|
* @return The integer ID of the Browser.
|
|
|
|
*/
|
|
|
|
private int getId() {
|
|
|
|
return mId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Load a URL resource into the Browser.
|
|
|
|
* @param url The URL string.
|
|
|
|
*/
|
|
|
|
public void loadUrl(String url) {
|
|
|
|
JSONObject args = new JSONObject();
|
|
|
|
try {
|
|
|
|
args.put("url", url);
|
|
|
|
args.put("parentId", -1);
|
|
|
|
args.put("newTab", false);
|
|
|
|
args.put("tabID", mId);
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.w(LOGTAG, "Error building JSON arguments for loadUrl.", e);
|
|
|
|
}
|
|
|
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Load", args.toString()));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reload the current URL resource into the Browser. The URL is force loaded from the
|
|
|
|
* network and is not pulled from cache.
|
|
|
|
*/
|
|
|
|
public void reload() {
|
|
|
|
Tab tab = Tabs.getInstance().getTab(mId);
|
|
|
|
if (tab != null) {
|
|
|
|
tab.doReload();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop the current loading operation.
|
|
|
|
*/
|
|
|
|
public void stop() {
|
|
|
|
Tab tab = Tabs.getInstance().getTab(mId);
|
|
|
|
if (tab != null) {
|
|
|
|
tab.doStop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check to see if the Browser has session history and can go back to a
|
|
|
|
* previous page.
|
|
|
|
* @return A boolean flag indicating if previous session exists.
|
|
|
|
* This method will likely be removed and replaced by a callback in GeckoViewContent
|
|
|
|
*/
|
|
|
|
public boolean canGoBack() {
|
|
|
|
Tab tab = Tabs.getInstance().getTab(mId);
|
|
|
|
if (tab != null) {
|
|
|
|
return tab.canDoBack();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Move backward in the session history, if that's possible.
|
|
|
|
*/
|
|
|
|
public void goBack() {
|
|
|
|
Tab tab = Tabs.getInstance().getTab(mId);
|
|
|
|
if (tab != null) {
|
|
|
|
tab.doBack();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check to see if the Browser has session history and can go forward to a
|
|
|
|
* new page.
|
|
|
|
* @return A boolean flag indicating if forward session exists.
|
|
|
|
* This method will likely be removed and replaced by a callback in GeckoViewContent
|
|
|
|
*/
|
|
|
|
public boolean canGoForward() {
|
|
|
|
Tab tab = Tabs.getInstance().getTab(mId);
|
|
|
|
if (tab != null) {
|
|
|
|
return tab.canDoForward();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Move forward in the session history, if that's possible.
|
|
|
|
*/
|
|
|
|
public void goForward() {
|
|
|
|
Tab tab = Tabs.getInstance().getTab(mId);
|
|
|
|
if (tab != null) {
|
|
|
|
tab.doForward();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-11-06 14:58:29 -08:00
|
|
|
|
2013-11-06 14:59:11 -08:00
|
|
|
/* Provides a means for the client to indicate whether a JavaScript
|
|
|
|
* dialog request should proceed. An instance of this class is passed to
|
|
|
|
* various GeckoViewChrome callback actions.
|
|
|
|
*/
|
|
|
|
public class PromptResult {
|
|
|
|
private final int RESULT_OK = 0;
|
|
|
|
private final int RESULT_CANCEL = 1;
|
|
|
|
|
2014-07-07 13:28:03 -07:00
|
|
|
private final JSONObject mMessage;
|
2013-11-06 14:59:11 -08:00
|
|
|
|
2014-07-07 13:28:03 -07:00
|
|
|
public PromptResult(JSONObject message) {
|
|
|
|
mMessage = message;
|
2013-11-06 14:59:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
private JSONObject makeResult(int resultCode) {
|
|
|
|
JSONObject result = new JSONObject();
|
|
|
|
try {
|
|
|
|
result.put("button", resultCode);
|
|
|
|
} catch(JSONException ex) { }
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle a confirmation response from the user.
|
|
|
|
*/
|
|
|
|
public void confirm() {
|
|
|
|
JSONObject result = makeResult(RESULT_OK);
|
2014-07-07 13:28:03 -07:00
|
|
|
EventDispatcher.sendResponse(mMessage, result);
|
2013-11-06 14:59:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle a confirmation response from the user.
|
|
|
|
* @param value String value to return to the browser context.
|
|
|
|
*/
|
|
|
|
public void confirmWithValue(String value) {
|
|
|
|
JSONObject result = makeResult(RESULT_OK);
|
|
|
|
try {
|
|
|
|
result.put("textbox0", value);
|
|
|
|
} catch(JSONException ex) { }
|
2014-07-07 13:28:03 -07:00
|
|
|
EventDispatcher.sendResponse(mMessage, result);
|
2013-11-06 14:59:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle a cancellation response from the user.
|
|
|
|
*/
|
|
|
|
public void cancel() {
|
|
|
|
JSONObject result = makeResult(RESULT_CANCEL);
|
2014-07-07 13:28:03 -07:00
|
|
|
EventDispatcher.sendResponse(mMessage, result);
|
2013-11-06 14:59:11 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-14 21:33:14 -07:00
|
|
|
/* Provides a means for the client to respond to a script message with some data.
|
|
|
|
* An instance of this class is passed to GeckoViewChrome.onScriptMessage.
|
|
|
|
*/
|
|
|
|
public class MessageResult {
|
|
|
|
private final EventCallback mCallback;
|
|
|
|
|
|
|
|
public MessageResult(EventCallback callback) {
|
|
|
|
if (callback == null) {
|
|
|
|
throw new IllegalArgumentException("EventCallback should not be null.");
|
|
|
|
}
|
|
|
|
mCallback = callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
private JSONObject bundleToJSON(Bundle data) {
|
|
|
|
JSONObject result = new JSONObject();
|
|
|
|
if (data == null) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
final Set<String> keys = data.keySet();
|
|
|
|
for (String key : keys) {
|
|
|
|
try {
|
|
|
|
result.put(key, data.get(key));
|
|
|
|
} catch (JSONException e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle a successful response to a script message.
|
|
|
|
* @param value Bundle value to return to the script context.
|
|
|
|
*/
|
|
|
|
public void success(Bundle data) {
|
|
|
|
mCallback.sendSuccess(bundleToJSON(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle a failure response to a script message.
|
|
|
|
*/
|
|
|
|
public void failure(Bundle data) {
|
|
|
|
mCallback.sendError(bundleToJSON(data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-06 14:58:29 -08:00
|
|
|
public interface ChromeDelegate {
|
|
|
|
/**
|
|
|
|
* Tell the host application that Gecko is ready to handle requests.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
*/
|
|
|
|
public void onReady(GeckoView view);
|
2013-11-06 14:59:11 -08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Tell the host application to display an alert dialog.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param browser The Browser that is loading the content.
|
|
|
|
* @param message The string to display in the dialog.
|
|
|
|
* @param result A PromptResult used to send back the result without blocking.
|
|
|
|
* Defaults to cancel requests.
|
|
|
|
*/
|
|
|
|
public void onAlert(GeckoView view, GeckoView.Browser browser, String message, GeckoView.PromptResult result);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tell the host application to display a confirmation dialog.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param browser The Browser that is loading the content.
|
|
|
|
* @param message The string to display in the dialog.
|
|
|
|
* @param result A PromptResult used to send back the result without blocking.
|
|
|
|
* Defaults to cancel requests.
|
|
|
|
*/
|
|
|
|
public void onConfirm(GeckoView view, GeckoView.Browser browser, String message, GeckoView.PromptResult result);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tell the host application to display an input prompt dialog.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param browser The Browser that is loading the content.
|
|
|
|
* @param message The string to display in the dialog.
|
|
|
|
* @param defaultValue The string to use as default input.
|
|
|
|
* @param result A PromptResult used to send back the result without blocking.
|
|
|
|
* Defaults to cancel requests.
|
|
|
|
*/
|
|
|
|
public void onPrompt(GeckoView view, GeckoView.Browser browser, String message, String defaultValue, GeckoView.PromptResult result);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tell the host application to display a remote debugging request dialog.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param result A PromptResult used to send back the result without blocking.
|
|
|
|
* Defaults to cancel requests.
|
|
|
|
*/
|
|
|
|
public void onDebugRequest(GeckoView view, GeckoView.PromptResult result);
|
2014-10-14 21:33:14 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Receive a message from an imported script.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param data Bundle of data sent with the message. Never null.
|
|
|
|
* @param result A MessageResult used to send back a response without blocking. Can be null.
|
|
|
|
* Defaults to do nothing.
|
|
|
|
*/
|
|
|
|
public void onScriptMessage(GeckoView view, Bundle data, GeckoView.MessageResult result);
|
2013-11-06 14:58:29 -08:00
|
|
|
}
|
2013-11-06 14:59:07 -08:00
|
|
|
|
|
|
|
public interface ContentDelegate {
|
|
|
|
/**
|
|
|
|
* A Browser has started loading content from the network.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param browser The Browser that is loading the content.
|
|
|
|
* @param url The resource being loaded.
|
|
|
|
*/
|
|
|
|
public void onPageStart(GeckoView view, GeckoView.Browser browser, String url);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A Browser has finished loading content from the network.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param browser The Browser that was loading the content.
|
|
|
|
* @param success Whether the page loaded successfully or an error occured.
|
|
|
|
*/
|
|
|
|
public void onPageStop(GeckoView view, GeckoView.Browser browser, boolean success);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A Browser is displaying content. This page could have been loaded via
|
|
|
|
* network or from the session history.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param browser The Browser that is showing the content.
|
|
|
|
*/
|
|
|
|
public void onPageShow(GeckoView view, GeckoView.Browser browser);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A page title was discovered in the content or updated after the content
|
|
|
|
* loaded.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param browser The Browser that is showing the content.
|
|
|
|
* @param title The title sent from the content.
|
|
|
|
*/
|
|
|
|
public void onReceivedTitle(GeckoView view, GeckoView.Browser browser, String title);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A link element was discovered in the content or updated after the content
|
|
|
|
* loaded that specifies a favicon.
|
|
|
|
* @param view The GeckoView that initiated the callback.
|
|
|
|
* @param browser The Browser that is showing the content.
|
|
|
|
* @param url The href of the link element specifying the favicon.
|
|
|
|
* @param size The maximum size specified for the favicon, or -1 for any size.
|
|
|
|
*/
|
|
|
|
public void onReceivedFavicon(GeckoView view, GeckoView.Browser browser, String url, int size);
|
|
|
|
}
|
|
|
|
|
2013-05-29 21:31:43 -07:00
|
|
|
}
|