mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
97ff754433
@ -140,6 +140,7 @@ MOZ_UPDATE_PACKAGING = @MOZ_UPDATE_PACKAGING@
|
||||
MOZ_DISABLE_PARENTAL_CONTROLS = @MOZ_DISABLE_PARENTAL_CONTROLS@
|
||||
NS_ENABLE_TSF = @NS_ENABLE_TSF@
|
||||
MOZ_SPELLCHECK = @MOZ_SPELLCHECK@
|
||||
MOZ_JAVA_COMPOSITOR = @MOZ_JAVA_COMPOSITOR@
|
||||
MOZ_PROFILELOCKING = @MOZ_PROFILELOCKING@
|
||||
MOZ_FEEDS = @MOZ_FEEDS@
|
||||
MOZ_TOOLKIT_SEARCH = @MOZ_TOOLKIT_SEARCH@
|
||||
|
@ -4662,6 +4662,7 @@ MOZ_REFLOW_PERF=
|
||||
MOZ_SAFE_BROWSING=
|
||||
MOZ_HELP_VIEWER=
|
||||
MOZ_SPELLCHECK=1
|
||||
MOZ_JAVA_COMPOSITOR=
|
||||
MOZ_SVG_DLISTS=
|
||||
MOZ_TOOLKIT_SEARCH=1
|
||||
MOZ_UI_LOCALE=en-US
|
||||
@ -8431,6 +8432,7 @@ AC_SUBST(IBMBIDI)
|
||||
AC_SUBST(MOZ_UNIVERSALCHARDET)
|
||||
AC_SUBST(ACCESSIBILITY)
|
||||
AC_SUBST(MOZ_SPELLCHECK)
|
||||
AC_SUBST(MOZ_JAVA_COMPOSITOR)
|
||||
AC_SUBST(MOZ_USER_DIR)
|
||||
AC_SUBST(MOZ_CRASHREPORTER)
|
||||
AC_SUBST(MOZ_UPDATER)
|
||||
|
@ -1955,6 +1955,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
||||
tmp->mAnimationController->Unlink();
|
||||
}
|
||||
|
||||
tmp->mPendingTitleChangeEvent.Revoke();
|
||||
|
||||
tmp->mInUnlinkOrDeletion = false;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
@ -62,6 +62,8 @@ import android.webkit.MimeTypeMap;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
|
||||
import android.provider.Settings;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import android.util.*;
|
||||
import android.net.Uri;
|
||||
@ -411,8 +413,6 @@ public class GeckoAppShell
|
||||
GeckoAppShell.nativeRun(combinedArgs);
|
||||
}
|
||||
|
||||
private static GeckoEvent mLastDrawEvent;
|
||||
|
||||
private static void sendPendingEventsToGecko() {
|
||||
try {
|
||||
while (!gPendingEvents.isEmpty()) {
|
||||
@ -1359,6 +1359,13 @@ public class GeckoAppShell
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean getAccessibilityEnabled() {
|
||||
AccessibilityManager accessibilityManager =
|
||||
(AccessibilityManager) GeckoApp.mAppContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
|
||||
return accessibilityManager.isEnabled();
|
||||
}
|
||||
|
||||
public static void addPluginView(final View view,
|
||||
final double x, final double y,
|
||||
final double w, final double h) {
|
||||
@ -1620,6 +1627,16 @@ public class GeckoAppShell
|
||||
}
|
||||
}
|
||||
|
||||
// unused
|
||||
public static String handleGeckoMessage(String message) {
|
||||
return "";
|
||||
}
|
||||
// unused
|
||||
static void checkUriVisited(String uri) {}
|
||||
// unused
|
||||
static void markUriVisited(final String uri) {}
|
||||
|
||||
|
||||
public static void enableBatteryNotifications() {
|
||||
GeckoBatteryManager.enableNotifications();
|
||||
}
|
||||
|
@ -73,6 +73,8 @@ public class GeckoEvent {
|
||||
public static final int SURFACE_DESTROYED = 14;
|
||||
public static final int GECKO_EVENT_SYNC = 15;
|
||||
public static final int ACTIVITY_START = 17;
|
||||
public static final int SAVE_STATE = 18;
|
||||
public static final int BROADCAST = 19;
|
||||
|
||||
public static final int IME_COMPOSITION_END = 0;
|
||||
public static final int IME_COMPOSITION_BEGIN = 1;
|
||||
@ -104,7 +106,7 @@ public class GeckoEvent {
|
||||
public int mMetaState, mFlags;
|
||||
public int mKeyCode, mUnicodeChar;
|
||||
public int mOffset, mCount;
|
||||
public String mCharacters;
|
||||
public String mCharacters, mCharactersExtra;
|
||||
public int mRangeType, mRangeStyles;
|
||||
public int mRangeForeColor, mRangeBackColor;
|
||||
public Location mLocation;
|
||||
@ -223,6 +225,12 @@ public class GeckoEvent {
|
||||
mP1 = new Point(screenw, screenh);
|
||||
}
|
||||
|
||||
public GeckoEvent(String subject, String data) {
|
||||
mType = BROADCAST;
|
||||
mCharacters = subject;
|
||||
mCharactersExtra = data;
|
||||
}
|
||||
|
||||
public GeckoEvent(String uri) {
|
||||
mType = LOAD_URI;
|
||||
mCharacters = uri;
|
||||
|
@ -21,8 +21,7 @@
|
||||
"test_privbrw_tabs.js",
|
||||
"test_bookmarks_in_same_named_folder.js",
|
||||
"test_client_wipe.js",
|
||||
"test_special_tabs.js",
|
||||
"test_mozmill_sanity.js"
|
||||
"test_special_tabs.js"
|
||||
]
|
||||
}
|
||||
|
||||
|
50
services/sync/tests/tps/test_addon_sanity.js
Normal file
50
services/sync/tests/tps/test_addon_sanity.js
Normal file
@ -0,0 +1,50 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* The list of phases mapped to their corresponding profiles. The object
|
||||
* here must be in strict JSON format, as it will get parsed by the Python
|
||||
* testrunner (no single quotes, extra comma's, etc).
|
||||
*/
|
||||
|
||||
var phases = { "phase1": "profile1",
|
||||
"phase2": "profile1",
|
||||
"phase3": "profile1",
|
||||
"phase4": "profile1",
|
||||
"phase5": "profile1" };
|
||||
|
||||
/*
|
||||
* Test phases
|
||||
*/
|
||||
|
||||
Phase('phase1', [
|
||||
[Addons.install, ['unsigned-1.0.xml']],
|
||||
[Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_DISABLED],
|
||||
[Sync, SYNC_WIPE_SERVER],
|
||||
]);
|
||||
|
||||
Phase('phase2', [
|
||||
[Sync],
|
||||
[Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_ENABLED],
|
||||
[Addons.setState, ['unsigned-xpi@tests.mozilla.org'], STATE_DISABLED],
|
||||
[Sync],
|
||||
]);
|
||||
|
||||
Phase('phase3', [
|
||||
[Sync],
|
||||
[Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_DISABLED],
|
||||
[Addons.setState, ['unsigned-xpi@tests.mozilla.org'], STATE_ENABLED],
|
||||
[Sync],
|
||||
]);
|
||||
|
||||
Phase('phase4', [
|
||||
[Sync],
|
||||
[Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_ENABLED],
|
||||
[Addons.uninstall, ['unsigned-xpi@tests.mozilla.org']],
|
||||
[Sync],
|
||||
]);
|
||||
|
||||
Phase('phase5', [
|
||||
[Sync],
|
||||
[Addons.verifyNot, ['unsigned-xpi@tests.mozilla.org']],
|
||||
]);
|
27
services/sync/tests/tps/unsigned-1.0.xml
Normal file
27
services/sync/tests/tps/unsigned-1.0.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<searchresults total_results="1">
|
||||
<addon id="5612">
|
||||
<name>Unsigned Test XPI</name>
|
||||
<type id="1">Extension</type>
|
||||
<guid>unsigned-xpi@tests.mozilla.org</guid>
|
||||
<slug>unsigned-xpi</slug>
|
||||
<version>1.0</version>
|
||||
|
||||
<compatible_applications><application>
|
||||
<name>Firefox</name>
|
||||
<application_id>1</application_id>
|
||||
<min_version>3.6</min_version>
|
||||
<max_version>*</max_version>
|
||||
<appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
|
||||
</application></compatible_applications>
|
||||
<all_compatible_os><os>ALL</os></all_compatible_os>
|
||||
|
||||
<install os="ALL" size="452">http://127.0.0.1:4567/unsigned-1.0.xpi</install>
|
||||
<created epoch="1252903662">
|
||||
2009-09-14T04:47:42Z
|
||||
</created>
|
||||
<last_updated epoch="1315255329">
|
||||
2011-09-05T20:42:09Z
|
||||
</last_updated>
|
||||
</addon>
|
||||
</searchresults>
|
BIN
services/sync/tests/tps/unsigned-1.0.xpi
Normal file
BIN
services/sync/tests/tps/unsigned-1.0.xpi
Normal file
Binary file not shown.
@ -30,9 +30,8 @@ tail =
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = os == "android"
|
||||
[test_errorhandler_sync_checkServerError.js]
|
||||
# Bug 604565: this test intermittently hangs on OS X debug builds.
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = (os == "mac" && debug) || os == "android"
|
||||
skip-if = os == "android"
|
||||
[test_forms_store.js]
|
||||
[test_forms_tracker.js]
|
||||
[test_history_engine.js]
|
||||
@ -80,13 +79,11 @@ skip-if = os == "win" || os == "android"
|
||||
[test_service_sync_401.js]
|
||||
[test_service_sync_locked.js]
|
||||
[test_service_sync_remoteSetup.js]
|
||||
# Bug 604565: this test intermittently hangs on OS X debug builds.
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = (os == "mac" && debug) || os == "android"
|
||||
skip-if = os == "android"
|
||||
[test_service_sync_updateEnabledEngines.js]
|
||||
# Bug 604565: this test intermittently hangs on OS X debug builds.
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = (os == "mac" && debug) || os == "android"
|
||||
skip-if = os == "android"
|
||||
[test_service_verifyLogin.js]
|
||||
[test_service_wipeClient.js]
|
||||
[test_service_wipeServer.js]
|
||||
@ -94,9 +91,8 @@ skip-if = (os == "mac" && debug) || os == "android"
|
||||
[test_status_checkSetup.js]
|
||||
[test_syncengine.js]
|
||||
[test_syncengine_sync.js]
|
||||
# Bug 604565: this test intermittently hangs on OS X debug builds.
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = (os == "mac" && debug) || os == "android"
|
||||
skip-if = os == "android"
|
||||
[test_syncscheduler.js]
|
||||
[test_syncstoragerequest.js]
|
||||
[test_tab_engine.js]
|
||||
|
252
services/sync/tps/extensions/tps/modules/addons.jsm
Normal file
252
services/sync/tps/extensions/tps/modules/addons.jsm
Normal file
@ -0,0 +1,252 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Crossweave.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonathan Griffin <jgriffin@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var EXPORTED_SYMBOLS = ["Addon", "STATE_ENABLED", "STATE_DISABLED"];
|
||||
|
||||
const CC = Components.classes;
|
||||
const CI = Components.interfaces;
|
||||
const CU = Components.utils;
|
||||
|
||||
CU.import("resource://gre/modules/AddonManager.jsm");
|
||||
CU.import("resource://gre/modules/AddonRepository.jsm");
|
||||
CU.import("resource://gre/modules/Services.jsm");
|
||||
CU.import("resource://services-sync/async.js");
|
||||
CU.import("resource://services-sync/util.js");
|
||||
CU.import("resource://tps/logger.jsm");
|
||||
var XPIProvider = CU.import("resource://gre/modules/XPIProvider.jsm")
|
||||
.XPIProvider;
|
||||
|
||||
const ADDONSGETURL = 'http://127.0.0.1:4567/';
|
||||
const STATE_ENABLED = 1;
|
||||
const STATE_DISABLED = 2;
|
||||
|
||||
function GetFileAsText(file)
|
||||
{
|
||||
let channel = Services.io.newChannel(file, null, null);
|
||||
let inputStream = channel.open();
|
||||
if (channel instanceof CI.nsIHttpChannel &&
|
||||
channel.responseStatus != 200) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let streamBuf = "";
|
||||
let sis = CC["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(CI.nsIScriptableInputStream);
|
||||
sis.init(inputStream);
|
||||
|
||||
let available;
|
||||
while ((available = sis.available()) != 0) {
|
||||
streamBuf += sis.read(available);
|
||||
}
|
||||
|
||||
inputStream.close();
|
||||
return streamBuf;
|
||||
}
|
||||
|
||||
function Addon(TPS, id) {
|
||||
this.TPS = TPS;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Addon.prototype = {
|
||||
_addons_requiring_restart: [],
|
||||
_addons_pending_install: [],
|
||||
|
||||
Delete: function() {
|
||||
// find our addon locally
|
||||
let cb = Async.makeSyncCallback();
|
||||
XPIProvider.getAddonsByTypes(null, cb);
|
||||
let results = Async.waitForSyncCallback(cb);
|
||||
var addon;
|
||||
var id = this.id;
|
||||
results.forEach(function(result) {
|
||||
if (result.id == id) {
|
||||
addon = result;
|
||||
}
|
||||
});
|
||||
Logger.AssertTrue(!!addon, 'could not find addon ' + this.id + ' to uninstall');
|
||||
addon.uninstall();
|
||||
},
|
||||
|
||||
Find: function(state) {
|
||||
let cb = Async.makeSyncCallback();
|
||||
let addon_found = false;
|
||||
var that = this;
|
||||
|
||||
var log_addon = function(addon) {
|
||||
that.addon = addon;
|
||||
Logger.logInfo('addon ' + addon.id + ' found, isActive: ' + addon.isActive);
|
||||
if (state == STATE_ENABLED || state == STATE_DISABLED) {
|
||||
Logger.AssertEqual(addon.isActive,
|
||||
state == STATE_ENABLED ? true : false,
|
||||
"addon " + that.id + " has an incorrect enabled state");
|
||||
}
|
||||
};
|
||||
|
||||
// first look in the list of all addons
|
||||
XPIProvider.getAddonsByTypes(null, cb);
|
||||
let addonlist = Async.waitForSyncCallback(cb);
|
||||
addonlist.forEach(function(addon) {
|
||||
if (addon.id == that.id) {
|
||||
addon_found = true;
|
||||
log_addon.call(that, addon);
|
||||
}
|
||||
});
|
||||
|
||||
if (!addon_found) {
|
||||
// then look in the list of recent installs
|
||||
cb = Async.makeSyncCallback();
|
||||
XPIProvider.getInstallsByTypes(null, cb);
|
||||
addonlist = Async.waitForSyncCallback(cb);
|
||||
for (var i in addonlist) {
|
||||
if (addonlist[i].addon && addonlist[i].addon.id == that.id &&
|
||||
addonlist[i].state == AddonManager.STATE_INSTALLED) {
|
||||
addon_found = true;
|
||||
log_addon.call(that, addonlist[i].addon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return addon_found;
|
||||
},
|
||||
|
||||
Install: function() {
|
||||
// For Install, the id parameter initially passed is really the filename
|
||||
// for the addon's install .xml; we'll read the actual id from the .xml.
|
||||
let url = this.id;
|
||||
|
||||
// set the url used by getAddonsByIDs
|
||||
var prefs = CC["@mozilla.org/preferences-service;1"]
|
||||
.getService(CI.nsIPrefBranch);
|
||||
prefs.setCharPref('extensions.getAddons.get.url', ADDONSGETURL + url);
|
||||
|
||||
// read the XML and find the addon id
|
||||
xml = GetFileAsText(ADDONSGETURL + url);
|
||||
Logger.AssertTrue(xml.indexOf("<guid>") > -1, 'guid not found in ' + url);
|
||||
this.id = xml.substring(xml.indexOf("<guid>") + 6, xml.indexOf("</guid"));
|
||||
Logger.logInfo('addon XML = ' + this.id);
|
||||
|
||||
// find our addon on 'AMO'
|
||||
let cb = Async.makeSyncCallback();
|
||||
AddonRepository.getAddonsByIDs([this.id], {
|
||||
searchSucceeded: cb,
|
||||
searchFailed: cb
|
||||
}, false);
|
||||
|
||||
// Result will be array of addons on searchSucceeded or undefined on
|
||||
// searchFailed.
|
||||
let install_addons = Async.waitForSyncCallback(cb);
|
||||
|
||||
Logger.AssertTrue(install_addons,
|
||||
"no addons found for id " + this.id);
|
||||
Logger.AssertEqual(install_addons.length,
|
||||
1,
|
||||
"multiple addons found for id " + this.id);
|
||||
|
||||
let addon = install_addons[0];
|
||||
Logger.logInfo(JSON.stringify(addon), null, ' ');
|
||||
if (XPIProvider.installRequiresRestart(addon)) {
|
||||
this._addons_requiring_restart.push(addon.id);
|
||||
}
|
||||
|
||||
// Start installing the addon asynchronously; finish up in
|
||||
// onInstallEnded(), onInstallFailed(), or onDownloadFailed().
|
||||
this._addons_pending_install.push(addon.id);
|
||||
this.TPS.StartAsyncOperation();
|
||||
|
||||
Utils.nextTick(function() {
|
||||
let callback = function(aInstall) {
|
||||
addon.install = aInstall;
|
||||
Logger.logInfo("addon install: " + addon.install);
|
||||
Logger.AssertTrue(addon.install,
|
||||
"could not get install object for id " + this.id);
|
||||
addon.install.addListener(this);
|
||||
addon.install.install();
|
||||
};
|
||||
|
||||
AddonManager.getInstallForURL(addon.sourceURI.spec,
|
||||
callback.bind(this),
|
||||
"application/x-xpinstall");
|
||||
}, this);
|
||||
},
|
||||
|
||||
SetState: function(state) {
|
||||
if (!this.Find())
|
||||
return false;
|
||||
this.addon.userDisabled = state == STATE_ENABLED ? false : true;
|
||||
return true;
|
||||
},
|
||||
|
||||
// addon installation callbacks
|
||||
onInstallEnded: function(addon) {
|
||||
try {
|
||||
Logger.logInfo('--------- event observed: addon onInstallEnded');
|
||||
Logger.AssertTrue(addon.addon,
|
||||
"No addon object in addon instance passed to onInstallEnded");
|
||||
Logger.AssertTrue(this._addons_pending_install.indexOf(addon.addon.id) > -1,
|
||||
"onInstallEnded received for unexpected addon " + addon.addon.id);
|
||||
this._addons_pending_install.splice(
|
||||
this._addons_pending_install.indexOf(addon.addon.id),
|
||||
1);
|
||||
}
|
||||
catch(e) {
|
||||
// We can't throw during a callback, as it will just get eaten by
|
||||
// the callback's caller.
|
||||
Utils.nextTick(function() {
|
||||
this.DumpError(e);
|
||||
}, this);
|
||||
return;
|
||||
}
|
||||
this.TPS.FinishAsyncOperation();
|
||||
},
|
||||
|
||||
onInstallFailed: function(addon) {
|
||||
Logger.logInfo('--------- event observed: addon onInstallFailed');
|
||||
Utils.nextTick(function() {
|
||||
this.DumpError('Installation failed for addon ' +
|
||||
(addon.addon && addon.addon.id ? addon.addon.id : 'unknown'));
|
||||
}, this);
|
||||
},
|
||||
|
||||
onDownloadFailed: function(addon) {
|
||||
Logger.logInfo('--------- event observed: addon onDownloadFailed');
|
||||
Utils.nextTick(function() {
|
||||
this.DumpError('Download failed for addon ' +
|
||||
(addon.addon && addon.addon.id ? addon.addon.id : 'unknown'));
|
||||
}, this);
|
||||
},
|
||||
|
||||
};
|
@ -48,9 +48,11 @@ const CU = Components.utils;
|
||||
|
||||
CU.import("resource://services-sync/service.js");
|
||||
CU.import("resource://services-sync/constants.js");
|
||||
CU.import("resource://services-sync/async.js");
|
||||
CU.import("resource://services-sync/util.js");
|
||||
CU.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
CU.import("resource://gre/modules/Services.jsm");
|
||||
CU.import("resource://tps/addons.jsm");
|
||||
CU.import("resource://tps/bookmarks.jsm");
|
||||
CU.import("resource://tps/logger.jsm");
|
||||
CU.import("resource://tps/passwords.jsm");
|
||||
@ -61,6 +63,8 @@ CU.import("resource://tps/tabs.jsm");
|
||||
|
||||
var hh = CC["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(CI.nsIHttpProtocolHandler);
|
||||
var prefs = CC["@mozilla.org/preferences-service;1"]
|
||||
.getService(CI.nsIPrefBranch);
|
||||
|
||||
var mozmillInit = {};
|
||||
CU.import('resource://mozmill/modules/init.js', mozmillInit);
|
||||
@ -73,37 +77,16 @@ const ACTION_SYNC = "sync";
|
||||
const ACTION_DELETE = "delete";
|
||||
const ACTION_PRIVATE_BROWSING = "private-browsing";
|
||||
const ACTION_WIPE_SERVER = "wipe-server";
|
||||
const ACTION_SETSTATE = "set-state";
|
||||
const ACTIONS = [ACTION_ADD, ACTION_VERIFY, ACTION_VERIFY_NOT,
|
||||
ACTION_MODIFY, ACTION_SYNC, ACTION_DELETE,
|
||||
ACTION_PRIVATE_BROWSING, ACTION_WIPE_SERVER];
|
||||
ACTION_PRIVATE_BROWSING, ACTION_WIPE_SERVER,
|
||||
ACTION_SETSTATE];
|
||||
|
||||
const SYNC_WIPE_SERVER = "wipe-server";
|
||||
const SYNC_RESET_CLIENT = "reset-client";
|
||||
const SYNC_WIPE_CLIENT = "wipe-client";
|
||||
|
||||
function GetFileAsText(file)
|
||||
{
|
||||
let channel = Services.io.newChannel(file, null, null);
|
||||
let inputStream = channel.open();
|
||||
if (channel instanceof CI.nsIHttpChannel &&
|
||||
channel.responseStatus != 200) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let streamBuf = "";
|
||||
let sis = CC["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(CI.nsIScriptableInputStream);
|
||||
sis.init(inputStream);
|
||||
|
||||
let available;
|
||||
while ((available = sis.available()) != 0) {
|
||||
streamBuf += sis.read(available);
|
||||
}
|
||||
|
||||
inputStream.close();
|
||||
return streamBuf;
|
||||
}
|
||||
|
||||
var TPS =
|
||||
{
|
||||
_waitingForSync: false,
|
||||
@ -351,6 +334,33 @@ var TPS =
|
||||
}
|
||||
},
|
||||
|
||||
HandleAddons: function (addons, action, state) {
|
||||
for (var i in addons) {
|
||||
Logger.logInfo("executing action " + action.toUpperCase() +
|
||||
" on addon " + JSON.stringify(addons[i]));
|
||||
var addon = new Addon(this, addons[i]);
|
||||
switch(action) {
|
||||
case ACTION_ADD:
|
||||
addon.Install();
|
||||
break;
|
||||
case ACTION_DELETE:
|
||||
addon.Delete();
|
||||
break;
|
||||
case ACTION_VERIFY:
|
||||
Logger.AssertTrue(addon.Find(state), 'addon ' + addon.id + ' not found');
|
||||
break;
|
||||
case ACTION_VERIFY_NOT:
|
||||
Logger.AssertTrue(!addon.Find(state), 'addon ' + addon.id + " is present, but it shouldn't be");
|
||||
break;
|
||||
case ACTION_SETSTATE:
|
||||
Logger.AssertTrue(addon.SetState(state), 'addon ' + addon.id + ' not found');
|
||||
break;
|
||||
}
|
||||
}
|
||||
Logger.logPass("executing action " + action.toUpperCase() +
|
||||
" on addons");
|
||||
},
|
||||
|
||||
HandleBookmarks: function (bookmarks, action) {
|
||||
try {
|
||||
let items = [];
|
||||
@ -460,7 +470,7 @@ var TPS =
|
||||
let phase = this._phaselist["phase" + this._currentPhase];
|
||||
let action = phase[this._currentAction];
|
||||
Logger.logInfo("starting action: " + JSON.stringify(action));
|
||||
action[0].call(this, action[1]);
|
||||
action[0].apply(this, action.slice(1));
|
||||
|
||||
// if we're in an async operation, don't continue on to the next action
|
||||
if (this._operations_pending)
|
||||
@ -517,8 +527,6 @@ var TPS =
|
||||
|
||||
// Store account details as prefs so they're accessible to the mozmill
|
||||
// framework.
|
||||
let prefs = CC["@mozilla.org/preferences-service;1"]
|
||||
.getService(CI.nsIPrefBranch);
|
||||
prefs.setCharPref('tps.account.username', this.config.account.username);
|
||||
prefs.setCharPref('tps.account.password', this.config.account.password);
|
||||
prefs.setCharPref('tps.account.passphrase', this.config.account.passphrase);
|
||||
@ -634,6 +642,24 @@ var TPS =
|
||||
},
|
||||
};
|
||||
|
||||
var Addons = {
|
||||
install: function Addons__install(addons) {
|
||||
TPS.HandleAddons(addons, ACTION_ADD);
|
||||
},
|
||||
setState: function Addons__setState(addons, state) {
|
||||
TPS.HandleAddons(addons, ACTION_SETSTATE, state);
|
||||
},
|
||||
uninstall: function Addons__uninstall(addons) {
|
||||
TPS.HandleAddons(addons, ACTION_DELETE);
|
||||
},
|
||||
verify: function Addons__verify(addons, state) {
|
||||
TPS.HandleAddons(addons, ACTION_VERIFY, state);
|
||||
},
|
||||
verifyNot: function Addons__verifyNot(addons) {
|
||||
TPS.HandleAddons(addons, ACTION_VERIFY_NOT);
|
||||
},
|
||||
};
|
||||
|
||||
var Bookmarks = {
|
||||
add: function Bookmarks__add(bookmarks) {
|
||||
TPS.HandleBookmarks(bookmarks, ACTION_ADD);
|
||||
|
@ -38,4 +38,5 @@
|
||||
from firefoxrunner import TPSFirefoxRunner
|
||||
from pulse import TPSPulseMonitor
|
||||
from testrunner import TPSTestRunner
|
||||
from mozhttpd import MozHttpd
|
||||
|
||||
|
111
testing/tps/tps/mozhttpd.py
Normal file
111
testing/tps/tps/mozhttpd.py
Normal file
@ -0,0 +1,111 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# the Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Joel Maher <joel.maher@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
import BaseHTTPServer
|
||||
import SimpleHTTPServer
|
||||
import threading
|
||||
import sys
|
||||
import os
|
||||
import urllib
|
||||
import re
|
||||
from urlparse import urlparse
|
||||
from SocketServer import ThreadingMixIn
|
||||
|
||||
DOCROOT = '.'
|
||||
|
||||
class EasyServer(ThreadingMixIn, BaseHTTPServer.HTTPServer):
|
||||
allow_reuse_address = True
|
||||
|
||||
class MozRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
def translate_path(self, path):
|
||||
# It appears that the default path is '/' and os.path.join makes the '/'
|
||||
o = urlparse(path)
|
||||
return "%s%s" % ('' if sys.platform == 'win32' else '/', '/'.join([i.strip('/') for i in (DOCROOT, o.path)]))
|
||||
|
||||
# I found on my local network that calls to this were timing out
|
||||
# I believe all of these calls are from log_message
|
||||
def address_string(self):
|
||||
return "a.b.c.d"
|
||||
|
||||
# This produces a LOT of noise
|
||||
def log_message(self, format, *args):
|
||||
pass
|
||||
|
||||
class MozHttpd(object):
|
||||
def __init__(self, host="127.0.0.1", port=8888, docroot='.'):
|
||||
global DOCROOT
|
||||
self.host = host
|
||||
self.port = int(port)
|
||||
DOCROOT = docroot
|
||||
|
||||
def start(self):
|
||||
self.httpd = EasyServer((self.host, self.port), MozRequestHandler)
|
||||
self.server = threading.Thread(target=self.httpd.serve_forever)
|
||||
self.server.setDaemon(True) # don't hang on exit
|
||||
self.server.start()
|
||||
#self.testServer()
|
||||
|
||||
#TODO: figure this out
|
||||
def testServer(self):
|
||||
fileList = os.listdir(DOCROOT)
|
||||
filehandle = urllib.urlopen('http://%s:%s' % (self.host, self.port))
|
||||
data = filehandle.readlines();
|
||||
filehandle.close()
|
||||
|
||||
for line in data:
|
||||
found = False
|
||||
# '@' denotes a symlink and we need to ignore it.
|
||||
webline = re.sub('\<[a-zA-Z0-9\-\_\.\=\"\'\/\\\%\!\@\#\$\^\&\*\(\) ]*\>', '', line.strip('\n')).strip('/').strip().strip('@')
|
||||
if webline != "":
|
||||
if webline == "Directory listing for":
|
||||
found = True
|
||||
else:
|
||||
for fileName in fileList:
|
||||
if fileName == webline:
|
||||
found = True
|
||||
|
||||
if (found == False):
|
||||
print "NOT FOUND: " + webline.strip()
|
||||
|
||||
def stop(self):
|
||||
if self.httpd:
|
||||
self.httpd.shutdown()
|
||||
|
||||
__del__ = stop
|
||||
|
@ -53,7 +53,7 @@ from mozprofile import Profile
|
||||
|
||||
from tps.firefoxrunner import TPSFirefoxRunner
|
||||
from tps.phase import TPSTestPhase
|
||||
|
||||
from tps.mozhttpd import MozHttpd
|
||||
|
||||
class TempFile(object):
|
||||
"""Class for temporary files that delete themselves when garbage-collected.
|
||||
@ -397,6 +397,9 @@ class TPSTestRunner(object):
|
||||
testlist = [os.path.basename(self.testfile)]
|
||||
testdir = os.path.dirname(self.testfile)
|
||||
|
||||
self.mozhttpd = MozHttpd(port=4567, docroot=testdir)
|
||||
self.mozhttpd.start()
|
||||
|
||||
# run each test, and save the results
|
||||
for test in testlist:
|
||||
result = self.run_single_test(testdir, test)
|
||||
@ -415,6 +418,8 @@ class TPSTestRunner(object):
|
||||
else:
|
||||
self.numfailed += 1
|
||||
|
||||
self.mozhttpd.stop()
|
||||
|
||||
# generate the postdata we'll use to post the results to the db
|
||||
self.postdata = { 'tests': self.results,
|
||||
'os':os_string,
|
||||
@ -440,7 +445,7 @@ class TPSTestRunner(object):
|
||||
self.numpassed,
|
||||
self.numfailed,
|
||||
self.config['account']['serverURL'],
|
||||
self.buildUrl)
|
||||
buildUrl)
|
||||
|
||||
subj = "TPS Report: "
|
||||
if self.numfailed == 0 and self.numpassed > 0:
|
||||
|
@ -161,6 +161,11 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
||||
jDisableBatteryNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableBatteryNotifications", "()V");
|
||||
jGetCurrentBatteryInformation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getCurrentBatteryInformation", "()[D");
|
||||
|
||||
jGetAccessibilityEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getAccessibilityEnabled", "()Z");
|
||||
jHandleGeckoMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "handleGeckoMessage", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
jCheckUriVisited = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "checkUriVisited", "(Ljava/lang/String;)V");
|
||||
jMarkUriVisited = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "markUriVisited", "(Ljava/lang/String;)V");
|
||||
|
||||
jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
|
||||
jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
|
||||
jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
|
||||
@ -670,6 +675,13 @@ AndroidBridge::HideProgressDialogOnce()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidBridge::GetAccessibilityEnabled()
|
||||
{
|
||||
ALOG_BRIDGE("AndroidBridge::GetAccessibilityEnabled");
|
||||
return mJNIEnv->CallStaticBooleanMethod(mGeckoAppShellClass, jGetAccessibilityEnabled);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::PerformHapticFeedback(bool aIsLongPress)
|
||||
{
|
||||
@ -839,6 +851,12 @@ AndroidBridge::SetSurfaceView(jobject obj)
|
||||
mSurfaceView.Init(obj);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::SetSoftwareLayerClient(jobject obj)
|
||||
{
|
||||
mSoftwareLayerClient.Init(obj);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::ShowInputMethodPicker()
|
||||
{
|
||||
@ -1002,10 +1020,8 @@ AndroidBridge::CreateShortcut(const nsAString& aTitle, const nsAString& aURI, co
|
||||
void
|
||||
AndroidBridge::PostToJavaThread(nsIRunnable* aRunnable, bool aMainThread)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "%s", __PRETTY_FUNCTION__);
|
||||
JNIEnv* env = AndroidBridge::AttachThread(false);
|
||||
if (!env) {
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "no jni env in %s!!", __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
mRunnableQueue.AppendObject(aRunnable);
|
||||
@ -1016,27 +1032,21 @@ AndroidBridge::PostToJavaThread(nsIRunnable* aRunnable, bool aMainThread)
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "leaving %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::ExecuteNextRunnable()
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "%s", __PRETTY_FUNCTION__);
|
||||
|
||||
JNIEnv* env = AndroidBridge::AttachThread(false);
|
||||
if (!env) {
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "no jni env in %s!!", __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRunnableQueue.Count() > 0) {
|
||||
nsIRunnable* r = mRunnableQueue[0];
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "going to run %p", r);
|
||||
r->Run();
|
||||
mRunnableQueue.RemoveObjectAt(0);
|
||||
}
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "leaving %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1269,6 +1279,54 @@ AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInf
|
||||
mJNIEnv->ReleaseDoubleArrayElements(arr, info, 0);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::HandleGeckoMessage(const nsAString &aMessage, nsAString &aRet)
|
||||
{
|
||||
ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
|
||||
JNIEnv* env = AndroidBridge::AttachThread(false);
|
||||
if (!env) {
|
||||
ALOG_BRIDGE("no jni env in %s!!", __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLocalJNIFrame jniFrame(1);
|
||||
jstring jMessage = mJNIEnv->NewString(nsPromiseFlatString(aMessage).get(), aMessage.Length());
|
||||
jstring returnMessage = static_cast<jstring>(env->CallStaticObjectMethod(mGeckoAppShellClass, jHandleGeckoMessage, jMessage));
|
||||
|
||||
jthrowable ex = env->ExceptionOccurred();
|
||||
if (ex) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
nsJNIString jniStr(returnMessage);
|
||||
aRet.Assign(jniStr);
|
||||
ALOG_BRIDGE("leaving %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::CheckURIVisited(const nsAString& aURI)
|
||||
{
|
||||
AutoLocalJNIFrame jniFrame(1);
|
||||
jstring jstrURI = mJNIEnv->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
|
||||
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jCheckUriVisited, jstrURI);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::MarkURIVisited(const nsAString& aURI)
|
||||
{
|
||||
AutoLocalJNIFrame jniFrame(1);
|
||||
jstring jstrURI = mJNIEnv->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
|
||||
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jMarkUriVisited, jstrURI);
|
||||
}
|
||||
|
||||
void AndroidBridge::EmitGeckoAccessibilityEvent (PRInt32 eventType, const nsAString& role, const nsAString& text, const nsAString& description, bool enabled, bool checked, bool password) {
|
||||
AutoLocalJNIFrame jniFrame;
|
||||
jstring jstrRole = mJNIEnv->NewString(nsPromiseFlatString(role).get(), role.Length());
|
||||
jstring jstrText = mJNIEnv->NewString(nsPromiseFlatString(text).get(), text.Length());
|
||||
jstring jstrDescription = mJNIEnv->NewString(nsPromiseFlatString(description).get(), description.Length());
|
||||
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEmitGeckoAccessibilityEvent, eventType, jstrRole, jstrText, jstrDescription, enabled, checked, password);
|
||||
}
|
||||
|
||||
void *
|
||||
AndroidBridge::LockBitmap(jobject bitmap)
|
||||
{
|
||||
@ -1379,3 +1437,21 @@ AndroidBridge::UnlockWindow(void* window)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Implementation file */
|
||||
NS_IMPL_ISUPPORTS1(nsAndroidBridge, nsIAndroidBridge)
|
||||
|
||||
nsAndroidBridge::nsAndroidBridge()
|
||||
{
|
||||
}
|
||||
|
||||
nsAndroidBridge::~nsAndroidBridge()
|
||||
{
|
||||
}
|
||||
|
||||
/* void handleGeckoEvent (in AString message); */
|
||||
NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(const nsAString & message, nsAString &aRet NS_OUTPARAM)
|
||||
{
|
||||
AndroidBridge::Bridge()->HandleGeckoMessage(message, aRet);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
@ -52,6 +53,8 @@
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "nsColor.h"
|
||||
|
||||
#include "nsIAndroidBridge.h"
|
||||
|
||||
// Some debug #defines
|
||||
// #define DEBUG_ANDROID_EVENTS
|
||||
// #define DEBUG_ANDROID_WIDGET
|
||||
@ -147,6 +150,9 @@ public:
|
||||
|
||||
void ScheduleRestart();
|
||||
|
||||
void SetSoftwareLayerClient(jobject jobj);
|
||||
AndroidGeckoSoftwareLayerClient &GetSoftwareLayerClient() { return mSoftwareLayerClient; }
|
||||
|
||||
void SetSurfaceView(jobject jobj);
|
||||
AndroidGeckoSurfaceView& SurfaceView() { return mSurfaceView; }
|
||||
|
||||
@ -222,6 +228,8 @@ public:
|
||||
|
||||
void FireAndWaitForTracerEvent();
|
||||
|
||||
bool GetAccessibilityEnabled();
|
||||
|
||||
struct AutoLocalJNIFrame {
|
||||
AutoLocalJNIFrame(int nEntries = 128) : mEntries(nEntries) {
|
||||
// Make sure there is enough space to store a local ref to the
|
||||
@ -290,6 +298,13 @@ public:
|
||||
bool LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride);
|
||||
bool UnlockWindow(void *window);
|
||||
|
||||
void HandleGeckoMessage(const nsAString& message, nsAString &aRet);
|
||||
|
||||
void EmitGeckoAccessibilityEvent (PRInt32 eventType, const nsAString& role, const nsAString& text, const nsAString& description, bool enabled, bool checked, bool password);
|
||||
|
||||
void CheckURIVisited(const nsAString& uri);
|
||||
void MarkURIVisited(const nsAString& uri);
|
||||
|
||||
bool InitCamera(const nsCString& contentType, PRUint32 camera, PRUint32 *width, PRUint32 *height, PRUint32 *fps);
|
||||
|
||||
void CloseCamera();
|
||||
@ -310,6 +325,7 @@ protected:
|
||||
|
||||
// the GeckoSurfaceView
|
||||
AndroidGeckoSurfaceView mSurfaceView;
|
||||
AndroidGeckoSoftwareLayerClient mSoftwareLayerClient;
|
||||
|
||||
// the GeckoAppShell java class
|
||||
jclass mGeckoAppShellClass;
|
||||
@ -375,6 +391,11 @@ protected:
|
||||
jmethodID jEnableBatteryNotifications;
|
||||
jmethodID jDisableBatteryNotifications;
|
||||
jmethodID jGetCurrentBatteryInformation;
|
||||
jmethodID jGetAccessibilityEnabled;
|
||||
jmethodID jHandleGeckoMessage;
|
||||
jmethodID jCheckUriVisited;
|
||||
jmethodID jMarkUriVisited;
|
||||
jmethodID jEmitGeckoAccessibilityEvent;
|
||||
|
||||
// stuff we need for CallEglCreateWindowSurface
|
||||
jclass jEGLSurfaceImplClass;
|
||||
@ -399,6 +420,24 @@ protected:
|
||||
|
||||
}
|
||||
|
||||
#define NS_ANDROIDBRIDGE_CID \
|
||||
{ 0x0FE2321D, 0xEBD9, 0x467D, \
|
||||
{ 0xA7, 0x43, 0x03, 0xA6, 0x8D, 0x40, 0x59, 0x9E } }
|
||||
|
||||
class nsAndroidBridge : public nsIAndroidBridge
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIANDROIDBRIDGE
|
||||
|
||||
nsAndroidBridge();
|
||||
|
||||
private:
|
||||
~nsAndroidBridge();
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
extern "C" JNIEnv * GetJNIForThread();
|
||||
extern bool mozilla_AndroidBridge_SetMainThread(void *);
|
||||
extern jclass GetGeckoAppShellClass();
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <jni.h>
|
||||
#include <pthread.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nsAppShell.h"
|
||||
#include "nsWindow.h"
|
||||
@ -52,6 +53,10 @@
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsINetworkLinkService.h"
|
||||
|
||||
#ifdef MOZ_ANDROID_HISTORY
|
||||
#include "nsAndroidHistory.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsICrashReporter.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
@ -66,6 +71,7 @@ extern "C" {
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *, jclass);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyGeckoOfEvent(JNIEnv *, jclass, jobject event);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_processNextNativeEvent(JNIEnv *, jclass);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setSoftwareLayerClient(JNIEnv *jenv, jclass, jobject sv);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setSurfaceView(JNIEnv *jenv, jclass, jobject sv);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *, jclass);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onLowMemory(JNIEnv *, jclass);
|
||||
@ -74,6 +80,7 @@ extern "C" {
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onChangeNetworkLinkStatus(JNIEnv *, jclass, jstring status);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *, jclass, jstring stack);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_executeNextRunnable(JNIEnv *, jclass);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited(JNIEnv *, jclass, jstring uri);
|
||||
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyBatteryChange(JNIEnv* jenv, jclass, jdouble, jboolean, jdouble);
|
||||
}
|
||||
|
||||
@ -110,6 +117,12 @@ Java_org_mozilla_gecko_GeckoAppShell_setSurfaceView(JNIEnv *jenv, jclass, jobjec
|
||||
AndroidBridge::Bridge()->SetSurfaceView(jenv->NewGlobalRef(obj));
|
||||
}
|
||||
|
||||
NS_EXPORT void JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_setSoftwareLayerClient(JNIEnv *jenv, jclass, jobject obj)
|
||||
{
|
||||
AndroidBridge::Bridge()->SetSoftwareLayerClient(jenv->NewGlobalRef(obj));
|
||||
}
|
||||
|
||||
NS_EXPORT void JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_onLowMemory(JNIEnv *jenv, jclass jc)
|
||||
{
|
||||
@ -189,6 +202,14 @@ Java_org_mozilla_gecko_GeckoAppShell_executeNextRunnable(JNIEnv *, jclass)
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoJNI", "leaving %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
NS_EXPORT void JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited(JNIEnv *jenv, jclass, jstring uri)
|
||||
{
|
||||
#ifdef MOZ_ANDROID_HISTORY
|
||||
nsAndroidHistory::NotifyURIVisited(nsJNIString(uri, jenv));
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_EXPORT void JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_notifyBatteryChange(JNIEnv* jenv, jclass,
|
||||
jdouble aLevel,
|
||||
|
@ -56,6 +56,7 @@ jfieldID AndroidGeckoEvent::jRectField = 0;
|
||||
jfieldID AndroidGeckoEvent::jNativeWindowField = 0;
|
||||
|
||||
jfieldID AndroidGeckoEvent::jCharactersField = 0;
|
||||
jfieldID AndroidGeckoEvent::jCharactersExtraField = 0;
|
||||
jfieldID AndroidGeckoEvent::jKeyCodeField = 0;
|
||||
jfieldID AndroidGeckoEvent::jMetaStateField = 0;
|
||||
jfieldID AndroidGeckoEvent::jFlagsField = 0;
|
||||
@ -102,6 +103,11 @@ jmethodID AndroidAddress::jGetSubLocalityMethod;
|
||||
jmethodID AndroidAddress::jGetSubThoroughfareMethod;
|
||||
jmethodID AndroidAddress::jGetThoroughfareMethod;
|
||||
|
||||
jclass AndroidGeckoSoftwareLayerClient::jGeckoSoftwareLayerClientClass = 0;
|
||||
jmethodID AndroidGeckoSoftwareLayerClient::jLockBufferMethod = 0;
|
||||
jmethodID AndroidGeckoSoftwareLayerClient::jUnlockBufferMethod = 0;
|
||||
jmethodID AndroidGeckoSoftwareLayerClient::jBeginDrawingMethod = 0;
|
||||
jmethodID AndroidGeckoSoftwareLayerClient::jEndDrawingMethod = 0;
|
||||
jclass AndroidGeckoSurfaceView::jGeckoSurfaceViewClass = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jBeginDrawingMethod = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jEndDrawingMethod = 0;
|
||||
@ -130,10 +136,12 @@ void
|
||||
mozilla::InitAndroidJavaWrappers(JNIEnv *jEnv)
|
||||
{
|
||||
AndroidGeckoEvent::InitGeckoEventClass(jEnv);
|
||||
AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(jEnv);
|
||||
AndroidPoint::InitPointClass(jEnv);
|
||||
AndroidLocation::InitLocationClass(jEnv);
|
||||
AndroidAddress::InitAddressClass(jEnv);
|
||||
AndroidRect::InitRectClass(jEnv);
|
||||
AndroidGeckoSoftwareLayerClient::InitGeckoSoftwareLayerClientClass(jEnv);
|
||||
AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(jEnv);
|
||||
}
|
||||
|
||||
void
|
||||
@ -157,6 +165,7 @@ AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
|
||||
jRectField = getField("mRect", "Landroid/graphics/Rect;");
|
||||
|
||||
jCharactersField = getField("mCharacters", "Ljava/lang/String;");
|
||||
jCharactersExtraField = getField("mCharactersExtra", "Ljava/lang/String;");
|
||||
jKeyCodeField = getField("mKeyCode", "I");
|
||||
jMetaStateField = getField("mMetaState", "I");
|
||||
jFlagsField = getField("mFlags", "I");
|
||||
@ -174,6 +183,7 @@ AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
|
||||
void
|
||||
AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(JNIEnv *jEnv)
|
||||
{
|
||||
#ifndef MOZ_JAVA_COMPOSITOR
|
||||
initInit();
|
||||
|
||||
jGeckoSurfaceViewClass = getClassGlobalRef("org/mozilla/gecko/GeckoSurfaceView");
|
||||
@ -186,6 +196,7 @@ AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(JNIEnv *jEnv)
|
||||
jDraw2DBufferMethod = getMethod("draw2D", "(Ljava/nio/ByteBuffer;I)V");
|
||||
jGetSurfaceMethod = getMethod("getSurface", "()Landroid/view/Surface;");
|
||||
jGetHolderMethod = getMethod("getHolder", "()Landroid/view/SurfaceHolder;");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -302,6 +313,22 @@ AndroidRect::InitRectClass(JNIEnv *jEnv)
|
||||
jRightField = getField("right", "I");
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoSoftwareLayerClient::InitGeckoSoftwareLayerClientClass(JNIEnv *jEnv)
|
||||
{
|
||||
#ifdef MOZ_JAVA_COMPOSITOR
|
||||
initInit();
|
||||
|
||||
jGeckoSoftwareLayerClientClass =
|
||||
getClassGlobalRef("org/mozilla/gecko/gfx/GeckoSoftwareLayerClient");
|
||||
|
||||
jLockBufferMethod = getMethod("lockBuffer", "()Ljava/nio/ByteBuffer;");
|
||||
jUnlockBufferMethod = getMethod("unlockBuffer", "()V");
|
||||
jBeginDrawingMethod = getMethod("beginDrawing", "()V");
|
||||
jEndDrawingMethod = getMethod("endDrawing", "(IIII)V");
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef initInit
|
||||
#undef initClassGlobalRef
|
||||
#undef getField
|
||||
@ -351,6 +378,27 @@ AndroidGeckoEvent::ReadCharactersField(JNIEnv *jenv)
|
||||
jenv->GetStringRegion(s, 0, len, mCharacters.BeginWriting());
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoEvent::ReadCharactersExtraField(JNIEnv *jenv)
|
||||
{
|
||||
jstring s = (jstring) jenv->GetObjectField(wrapped_obj, jCharactersExtraField);
|
||||
if (!s) {
|
||||
mCharactersExtra.SetIsVoid(PR_TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
int len = jenv->GetStringLength(s);
|
||||
mCharactersExtra.SetLength(len);
|
||||
jenv->GetStringRegion(s, 0, len, mCharactersExtra.BeginWriting());
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoEvent::Init(int aType, nsIntRect const& aRect)
|
||||
{
|
||||
mType = aType;
|
||||
mRect = aRect;
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
@ -437,6 +485,17 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
|
||||
break;
|
||||
}
|
||||
|
||||
case BROADCAST: {
|
||||
ReadCharactersField(jenv);
|
||||
ReadCharactersExtraField(jenv);
|
||||
break;
|
||||
}
|
||||
|
||||
case SAVE_STATE: {
|
||||
ReadCharactersField(jenv);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -472,6 +531,25 @@ AndroidGeckoEvent::Init(AndroidGeckoEvent *aResizeEvent)
|
||||
mP1.y = aResizeEvent->mP1.y;
|
||||
}
|
||||
|
||||
void
|
||||
AndroidPoint::Init(JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
if (jobj) {
|
||||
mX = jenv->GetIntField(jobj, jXField);
|
||||
mY = jenv->GetIntField(jobj, jYField);
|
||||
} else {
|
||||
mX = 0;
|
||||
mY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoSoftwareLayerClient::Init(jobject jobj)
|
||||
{
|
||||
NS_ASSERTION(wrapped_obj == nsnull, "Init called on non-null wrapped_obj!");
|
||||
wrapped_obj = jobj;
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoSurfaceView::Init(jobject jobj)
|
||||
{
|
||||
@ -506,6 +584,46 @@ AndroidGeckoSurfaceView::Draw2D(jobject buffer, int stride)
|
||||
JNI()->CallVoidMethod(wrapped_obj, jDraw2DBufferMethod, buffer, stride);
|
||||
}
|
||||
|
||||
jobject
|
||||
AndroidGeckoSoftwareLayerClient::LockBuffer()
|
||||
{
|
||||
NS_ASSERTION(!isNull(), "LockBuffer() called on null software layer client!");
|
||||
AndroidBridge::AutoLocalJNIFrame(1);
|
||||
return JNI()->CallObjectMethod(wrapped_obj, jLockBufferMethod);
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
AndroidGeckoSoftwareLayerClient::LockBufferBits()
|
||||
{
|
||||
AndroidBridge::AutoLocalJNIFrame(1);
|
||||
return reinterpret_cast<unsigned char *>(JNI()->GetDirectBufferAddress(LockBuffer()));
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoSoftwareLayerClient::UnlockBuffer()
|
||||
{
|
||||
NS_ASSERTION(!isNull(), "UnlockBuffer() called on null software layer client!");
|
||||
AndroidBridge::AutoLocalJNIFrame(1);
|
||||
JNI()->CallVoidMethod(wrapped_obj, jUnlockBufferMethod);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoSoftwareLayerClient::BeginDrawing()
|
||||
{
|
||||
NS_ASSERTION(!isNull(), "BeginDrawing() called on null software layer client!");
|
||||
AndroidBridge::AutoLocalJNIFrame(1);
|
||||
return JNI()->CallVoidMethod(wrapped_obj, jBeginDrawingMethod);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoSoftwareLayerClient::EndDrawing(const nsIntRect &aRect)
|
||||
{
|
||||
NS_ASSERTION(!isNull(), "EndDrawing() called on null software layer client!");
|
||||
AndroidBridge::AutoLocalJNIFrame(1);
|
||||
return JNI()->CallVoidMethod(wrapped_obj, jEndDrawingMethod, aRect.x, aRect.y, aRect.width,
|
||||
aRect.height);
|
||||
}
|
||||
|
||||
jobject
|
||||
AndroidGeckoSurfaceView::GetSoftwareDrawBitmap()
|
||||
{
|
||||
@ -530,22 +648,6 @@ AndroidGeckoSurfaceView::GetSurfaceHolder()
|
||||
return JNI()->CallObjectMethod(wrapped_obj, jGetHolderMethod);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidPoint::Init(JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
NS_ASSERTION(wrapped_obj == nsnull, "Init called on non-null wrapped_obj!");
|
||||
|
||||
wrapped_obj = jobj;
|
||||
|
||||
if (jobj) {
|
||||
mX = jenv->GetIntField(jobj, jXField);
|
||||
mY = jenv->GetIntField(jobj, jYField);
|
||||
} else {
|
||||
mX = 0;
|
||||
mY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AndroidRect::Init(JNIEnv *jenv, jobject jobj)
|
||||
{
|
||||
|
@ -149,6 +149,32 @@ protected:
|
||||
static jfieldID jTopField;
|
||||
};
|
||||
|
||||
class AndroidGeckoSoftwareLayerClient : public WrappedJavaObject {
|
||||
public:
|
||||
static void InitGeckoSoftwareLayerClientClass(JNIEnv *jEnv);
|
||||
|
||||
void Init(jobject jobj);
|
||||
|
||||
AndroidGeckoSoftwareLayerClient() {}
|
||||
AndroidGeckoSoftwareLayerClient(jobject jobj) { Init(jobj); }
|
||||
|
||||
jobject LockBuffer();
|
||||
unsigned char *LockBufferBits();
|
||||
void UnlockBuffer();
|
||||
void BeginDrawing();
|
||||
void EndDrawing(const nsIntRect &aRect);
|
||||
|
||||
private:
|
||||
static jclass jGeckoSoftwareLayerClientClass;
|
||||
static jmethodID jLockBufferMethod;
|
||||
static jmethodID jUnlockBufferMethod;
|
||||
|
||||
protected:
|
||||
static jmethodID jBeginDrawingMethod;
|
||||
static jmethodID jEndDrawingMethod;
|
||||
};
|
||||
|
||||
|
||||
class AndroidGeckoSurfaceView : public WrappedJavaObject
|
||||
{
|
||||
public:
|
||||
@ -388,6 +414,9 @@ public:
|
||||
AndroidGeckoEvent(int x1, int y1, int x2, int y2) {
|
||||
Init(x1, y1, x2, y2);
|
||||
}
|
||||
AndroidGeckoEvent(int aType, const nsIntRect &aRect) {
|
||||
Init(aType, aRect);
|
||||
}
|
||||
AndroidGeckoEvent(JNIEnv *jenv, jobject jobj) {
|
||||
Init(jenv, jobj);
|
||||
}
|
||||
@ -398,6 +427,7 @@ public:
|
||||
void Init(JNIEnv *jenv, jobject jobj);
|
||||
void Init(int aType);
|
||||
void Init(int x1, int y1, int x2, int y2);
|
||||
void Init(int aType, const nsIntRect &aRect);
|
||||
void Init(AndroidGeckoEvent *aResizeEvent);
|
||||
|
||||
int Action() { return mAction; }
|
||||
@ -413,6 +443,7 @@ public:
|
||||
double Z() { return mZ; }
|
||||
const nsIntRect& Rect() { return mRect; }
|
||||
nsAString& Characters() { return mCharacters; }
|
||||
nsAString& CharactersExtra() { return mCharactersExtra; }
|
||||
int KeyCode() { return mKeyCode; }
|
||||
int MetaState() { return mMetaState; }
|
||||
int Flags() { return mFlags; }
|
||||
@ -440,7 +471,7 @@ protected:
|
||||
int mRangeForeColor, mRangeBackColor;
|
||||
double mAlpha, mBeta, mGamma;
|
||||
double mX, mY, mZ;
|
||||
nsString mCharacters;
|
||||
nsString mCharacters, mCharactersExtra;
|
||||
nsRefPtr<nsGeoPosition> mGeoPosition;
|
||||
nsRefPtr<nsGeoPositionAddress> mGeoAddress;
|
||||
|
||||
@ -448,6 +479,7 @@ protected:
|
||||
void ReadP1Field(JNIEnv *jenv);
|
||||
void ReadRectField(JNIEnv *jenv);
|
||||
void ReadCharactersField(JNIEnv *jenv);
|
||||
void ReadCharactersExtraField(JNIEnv *jenv);
|
||||
|
||||
static jclass jGeckoEventClass;
|
||||
static jfieldID jActionField;
|
||||
@ -465,6 +497,7 @@ protected:
|
||||
static jfieldID jNativeWindowField;
|
||||
|
||||
static jfieldID jCharactersField;
|
||||
static jfieldID jCharactersExtraField;
|
||||
static jfieldID jKeyCodeField;
|
||||
static jfieldID jMetaStateField;
|
||||
static jfieldID jFlagsField;
|
||||
@ -498,6 +531,8 @@ public:
|
||||
GECKO_EVENT_SYNC = 15,
|
||||
FORCED_RESIZE = 16,
|
||||
ACTIVITY_START = 17,
|
||||
SAVE_STATE = 18,
|
||||
BROADCAST = 19,
|
||||
dummy_java_enum_list_end
|
||||
};
|
||||
|
||||
|
@ -44,12 +44,16 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = widget
|
||||
LIBRARY_NAME = widget_android
|
||||
XPIDL_MODULE = widget_android
|
||||
EXPORT_LIBRARY = 1
|
||||
IS_COMPONENT = 1
|
||||
MODULE_NAME = nsWidgetAndroidModule
|
||||
GRE_MODULE = 1
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
ifdef MOZ_JAVA_COMPOSITOR
|
||||
DEFINES += -DMOZ_JAVA_COMPOSITOR
|
||||
endif
|
||||
|
||||
CPPSRCS = \
|
||||
GfxInfo.cpp \
|
||||
@ -78,6 +82,10 @@ NOT_THERE_YET_CPPSRCS = \
|
||||
nsSound.cpp \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIAndroidBridge.idl \
|
||||
$(NULL)
|
||||
|
||||
SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a
|
||||
|
||||
EXPORTS = AndroidBridge.h AndroidJavaWrappers.h
|
||||
@ -91,6 +99,8 @@ LOCAL_INCLUDES += \
|
||||
-I$(topsrcdir)/widget/src/xpwidgets \
|
||||
-I$(topsrcdir)/widget/src/shared \
|
||||
-I$(topsrcdir)/dom/system/android \
|
||||
-I$(topsrcdir)/toolkit/components/places \
|
||||
-I$(topsrcdir)/docshell/base \
|
||||
-I$(srcdir) \
|
||||
$(NULL)
|
||||
|
||||
|
@ -368,12 +368,30 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
||||
break;
|
||||
}
|
||||
|
||||
case AndroidGeckoEvent::BROADCAST: {
|
||||
|
||||
if (curEvent->Characters().Length() == 0)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
const NS_ConvertUTF16toUTF8 topic(curEvent->Characters());
|
||||
const nsPromiseFlatString& data = PromiseFlatString(curEvent->CharactersExtra());
|
||||
|
||||
obsServ->NotifyObservers(nsnull, topic.get(), data.get());
|
||||
break;
|
||||
}
|
||||
|
||||
case AndroidGeckoEvent::LOAD_URI: {
|
||||
nsCOMPtr<nsICommandLineRunner> cmdline
|
||||
(do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
|
||||
if (!cmdline)
|
||||
break;
|
||||
|
||||
if (curEvent->Characters().Length() == 0)
|
||||
break;
|
||||
|
||||
char *uri = ToNewUTF8String(curEvent->Characters());
|
||||
if (!uri)
|
||||
break;
|
||||
|
7
widget/src/android/nsIAndroidBridge.idl
Normal file
7
widget/src/android/nsIAndroidBridge.idl
Normal file
@ -0,0 +1,7 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(32c345d4-9f45-446a-8a93-8939f3453e87)]
|
||||
interface nsIAndroidBridge : nsISupports
|
||||
{
|
||||
AString handleGeckoMessage(in AString message);
|
||||
};
|
@ -41,6 +41,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsAppShell.h"
|
||||
#include "AndroidBridge.h"
|
||||
|
||||
#include "nsWindow.h"
|
||||
#include "nsLookAndFeel.h"
|
||||
@ -71,6 +72,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintSession, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceContextSpecAndroid)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIMEPicker)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAndroidBridge)
|
||||
|
||||
#include "GfxInfo.h"
|
||||
namespace mozilla {
|
||||
@ -113,6 +115,7 @@ NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_HTMLFORMATCONVERTER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_IMEPICKER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_GFXINFO_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ANDROIDBRIDGE_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
|
||||
{ &kNS_WINDOW_CID, false, NULL, nsWindowConstructor },
|
||||
@ -130,6 +133,7 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
|
||||
{ &kNS_HTMLFORMATCONVERTER_CID, false, NULL, nsHTMLFormatConverterConstructor },
|
||||
{ &kNS_IMEPICKER_CID, false, NULL, nsIMEPickerConstructor },
|
||||
{ &kNS_GFXINFO_CID, false, NULL, mozilla::widget::GfxInfoConstructor },
|
||||
{ &kNS_ANDROIDBRIDGE_CID, false, NULL, nsAndroidBridgeConstructor },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -149,6 +153,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
|
||||
{ "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID },
|
||||
{ "@mozilla.org/imepicker;1", &kNS_IMEPICKER_CID },
|
||||
{ "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },
|
||||
{ "@mozilla.org/android/bridge;1", &kNS_ANDROIDBRIDGE_CID },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -75,6 +75,14 @@ using mozilla::unused;
|
||||
|
||||
#include "AndroidBridge.h"
|
||||
|
||||
#include "imgIEncoder.h"
|
||||
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
// NB: Keep these in sync with LayerController.java in embedding/android/.
|
||||
#define TILE_WIDTH 1024
|
||||
#define TILE_HEIGHT 2048
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
|
||||
@ -83,6 +91,10 @@ NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
|
||||
static gfxIntSize gAndroidBounds;
|
||||
static gfxIntSize gAndroidScreenBounds;
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
bool nsWindow::sAccessibilityEnabled = false;
|
||||
#endif
|
||||
|
||||
class ContentCreationNotifier;
|
||||
static nsCOMPtr<ContentCreationNotifier> gContentCreationNotifier;
|
||||
// A helper class to send updates when content processes
|
||||
@ -176,6 +188,9 @@ nsWindow::nsWindow() :
|
||||
mIsVisible(false),
|
||||
mParent(nsnull),
|
||||
mFocus(nsnull),
|
||||
#ifdef ACCESSIBILITY
|
||||
mRootAccessible(nsnull),
|
||||
#endif
|
||||
mIMEComposing(false)
|
||||
{
|
||||
}
|
||||
@ -186,6 +201,10 @@ nsWindow::~nsWindow()
|
||||
nsWindow *top = FindTopLevel();
|
||||
if (top->mFocus == this)
|
||||
top->mFocus = nsnull;
|
||||
#ifdef ACCESSIBILITY
|
||||
if (mRootAccessible)
|
||||
mRootAccessible = nsnull;
|
||||
#endif
|
||||
ALOG("nsWindow %p destructor", (void*)this);
|
||||
}
|
||||
|
||||
@ -283,6 +302,15 @@ nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& config)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::RedrawAll()
|
||||
{
|
||||
nsIntRect entireRect(0, 0, TILE_WIDTH, TILE_HEIGHT);
|
||||
AndroidGeckoEvent *event = new AndroidGeckoEvent(AndroidGeckoEvent::DRAW,
|
||||
entireRect);
|
||||
nsAppShell::gAppShell->PostEvent(event);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::SetParent(nsIWidget *aNewParent)
|
||||
{
|
||||
@ -303,7 +331,7 @@ nsWindow::SetParent(nsIWidget *aNewParent)
|
||||
|
||||
// if we are now in the toplevel window's hierarchy, schedule a redraw
|
||||
if (FindTopLevel() == TopWindow())
|
||||
nsAppShell::gAppShell->PostEvent(new AndroidGeckoEvent(-1, -1, -1, -1));
|
||||
RedrawAll();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -371,9 +399,20 @@ nsWindow::Show(bool aState)
|
||||
}
|
||||
}
|
||||
} else if (FindTopLevel() == TopWindow()) {
|
||||
nsAppShell::gAppShell->PostEvent(new AndroidGeckoEvent(-1, -1, -1, -1));
|
||||
RedrawAll();
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
static bool sAccessibilityChecked = false;
|
||||
if (!sAccessibilityChecked) {
|
||||
sAccessibilityChecked = true;
|
||||
sAccessibilityEnabled =
|
||||
AndroidBridge::Bridge()->GetAccessibilityEnabled();
|
||||
}
|
||||
if (aState && sAccessibilityEnabled)
|
||||
CreateRootAccessible();
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ANDROID_WIDGET
|
||||
DumpWindows();
|
||||
#endif
|
||||
@ -381,6 +420,32 @@ nsWindow::Show(bool aState)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
void
|
||||
nsWindow::CreateRootAccessible()
|
||||
{
|
||||
if (IsTopLevel() && !mRootAccessible) {
|
||||
ALOG(("nsWindow:: Create Toplevel Accessibility\n"));
|
||||
nsAccessible *acc = DispatchAccessibleEvent();
|
||||
|
||||
if (acc) {
|
||||
mRootAccessible = acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
nsWindow::DispatchAccessibleEvent()
|
||||
{
|
||||
nsAccessibleEvent event(true, NS_GETACCESSIBLE, this);
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
|
||||
return event.mAccessible;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::SetModal(bool aState)
|
||||
{
|
||||
@ -459,7 +524,7 @@ nsWindow::Resize(PRInt32 aX,
|
||||
|
||||
// Should we skip honoring aRepaint here?
|
||||
if (aRepaint && FindTopLevel() == TopWindow())
|
||||
nsAppShell::gAppShell->PostEvent(new AndroidGeckoEvent(-1, -1, -1, -1));
|
||||
RedrawAll();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -512,7 +577,8 @@ NS_IMETHODIMP
|
||||
nsWindow::Invalidate(const nsIntRect &aRect,
|
||||
bool aIsSynchronous)
|
||||
{
|
||||
nsAppShell::gAppShell->PostEvent(new AndroidGeckoEvent(-1, -1, -1, -1));
|
||||
AndroidGeckoEvent *event = new AndroidGeckoEvent(AndroidGeckoEvent::DRAW, aRect);
|
||||
nsAppShell::gAppShell->PostEvent(event);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -588,7 +654,7 @@ nsWindow::BringToFront()
|
||||
|
||||
// force a window resize
|
||||
nsAppShell::gAppShell->ResendLastResizeEvent(this);
|
||||
nsAppShell::gAppShell->PostEvent(new AndroidGeckoEvent(-1, -1, -1, -1));
|
||||
RedrawAll();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -730,6 +796,66 @@ nsWindow::GetThebesSurface()
|
||||
return new gfxImageSurface(gfxIntSize(5,5), gfxImageSurface::ImageFormatRGB24);
|
||||
}
|
||||
|
||||
bool
|
||||
nsWindow::DrawToFile(const nsAString &path)
|
||||
{
|
||||
if (!IsTopLevel() || !mIsVisible) {
|
||||
ALOG("### DrawToFile works only for a visible toplevel window!");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (GetLayerManager(nsnull)->GetBackendType() != LayerManager::LAYERS_BASIC) {
|
||||
ALOG("### DrawToFile works only for a basic layers!");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxImageSurface> imgSurface =
|
||||
new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
|
||||
gfxImageSurface::ImageFormatARGB32);
|
||||
|
||||
if (imgSurface->CairoStatus()) {
|
||||
ALOG("### Failed to create a valid surface");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIntRect boundsRect(0, 0, mBounds.width, mBounds.height);
|
||||
bool result = DrawTo(imgSurface, boundsRect);
|
||||
NS_ENSURE_TRUE(result, PR_FALSE);
|
||||
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
|
||||
NS_ENSURE_TRUE(encoder, PR_FALSE);
|
||||
|
||||
encoder->InitFromData(imgSurface->Data(),
|
||||
imgSurface->Stride() * mBounds.height,
|
||||
mBounds.width,
|
||||
mBounds.height,
|
||||
imgSurface->Stride(),
|
||||
imgIEncoder::INPUT_FORMAT_HOSTARGB,
|
||||
EmptyString());
|
||||
|
||||
nsCOMPtr<nsILocalFile> file;
|
||||
NS_NewLocalFile(path, true, getter_AddRefs(file));
|
||||
NS_ENSURE_TRUE(file, PR_FALSE);
|
||||
|
||||
PRUint32 length;
|
||||
encoder->Available(&length);
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
|
||||
NS_ENSURE_TRUE(outputStream, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
|
||||
NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
|
||||
outputStream, length);
|
||||
NS_ENSURE_TRUE(bufferedOutputStream, PR_FALSE);
|
||||
|
||||
PRUint32 numWritten;
|
||||
bufferedOutputStream->WriteFrom(encoder, length, &numWritten);
|
||||
NS_ENSURE_SUCCESS(length == numWritten, PR_FALSE);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
|
||||
{
|
||||
@ -882,6 +1008,10 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
|
||||
AndroidBridge::Bridge()->AcknowledgeEventSync();
|
||||
break;
|
||||
|
||||
case AndroidGeckoEvent::SAVE_STATE:
|
||||
win->DrawToFile(ae->Characters());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -906,6 +1036,13 @@ nsWindow::OnAndroidEvent(AndroidGeckoEvent *ae)
|
||||
|
||||
bool
|
||||
nsWindow::DrawTo(gfxASurface *targetSurface)
|
||||
{
|
||||
nsIntRect boundsRect(0, 0, mBounds.width, mBounds.height);
|
||||
return DrawTo(targetSurface, boundsRect);
|
||||
}
|
||||
|
||||
bool
|
||||
nsWindow::DrawTo(gfxASurface *targetSurface, const nsIntRect &invalidRect)
|
||||
{
|
||||
if (!mIsVisible)
|
||||
return false;
|
||||
@ -927,7 +1064,7 @@ nsWindow::DrawTo(gfxASurface *targetSurface)
|
||||
// If we have no covering child, then we need to render this.
|
||||
if (coveringChildIndex == -1) {
|
||||
nsPaintEvent event(true, NS_PAINT, this);
|
||||
event.region = boundsRect;
|
||||
event.region = boundsRect.Intersect(invalidRect);
|
||||
switch (GetLayerManager(nsnull)->GetBackendType()) {
|
||||
case LayerManager::LAYERS_BASIC: {
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
|
||||
@ -982,7 +1119,7 @@ nsWindow::DrawTo(gfxASurface *targetSurface)
|
||||
targetSurface->SetDeviceOffset(offset + gfxPoint(mChildren[i]->mBounds.x,
|
||||
mChildren[i]->mBounds.y));
|
||||
|
||||
bool ok = mChildren[i]->DrawTo(targetSurface);
|
||||
bool ok = mChildren[i]->DrawTo(targetSurface, invalidRect);
|
||||
|
||||
if (!ok) {
|
||||
ALOG("nsWindow[%p]::DrawTo child %d[%p] returned FALSE!", (void*) this, i, (void*)mChildren[i]);
|
||||
@ -998,11 +1135,6 @@ nsWindow::DrawTo(gfxASurface *targetSurface)
|
||||
void
|
||||
nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||
{
|
||||
|
||||
if (!sSurfaceExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsTopLevel()) {
|
||||
ALOG("##### redraw for window %p, which is not a toplevel window -- sending to toplevel!", (void*) this);
|
||||
DumpWindows();
|
||||
@ -1016,6 +1148,27 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||
}
|
||||
|
||||
AndroidBridge::AutoLocalJNIFrame jniFrame;
|
||||
#ifdef MOZ_JAVA_COMPOSITOR
|
||||
AndroidGeckoSoftwareLayerClient &client =
|
||||
AndroidBridge::Bridge()->GetSoftwareLayerClient();
|
||||
client.BeginDrawing();
|
||||
unsigned char *bits = client.LockBufferBits();
|
||||
nsRefPtr<gfxImageSurface> targetSurface =
|
||||
new gfxImageSurface(bits, gfxIntSize(TILE_WIDTH, TILE_HEIGHT), TILE_WIDTH * 2,
|
||||
gfxASurface::ImageFormatRGB16_565);
|
||||
if (targetSurface->CairoStatus()) {
|
||||
ALOG("### Failed to create a valid surface from the bitmap");
|
||||
} else {
|
||||
DrawTo(targetSurface, ae->Rect());
|
||||
client.UnlockBuffer();
|
||||
client.EndDrawing(ae->Rect());
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!sSurfaceExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
AndroidGeckoSurfaceView& sview(AndroidBridge::Bridge()->SurfaceView());
|
||||
|
||||
|
@ -43,6 +43,10 @@
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "nsAccessible.h"
|
||||
#endif
|
||||
|
||||
class gfxASurface;
|
||||
class nsIdleService;
|
||||
|
||||
@ -167,10 +171,17 @@ public:
|
||||
gfxASurface* GetThebesSurface();
|
||||
|
||||
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
static bool sAccessibilityEnabled;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void BringToFront();
|
||||
nsWindow *FindTopLevel();
|
||||
bool DrawTo(gfxASurface *targetSurface);
|
||||
bool DrawTo(gfxASurface *targetSurface, const nsIntRect &aRect);
|
||||
bool DrawToFile(const nsAString &path);
|
||||
bool IsTopLevel();
|
||||
void OnIMEAddRange(mozilla::AndroidGeckoEvent *ae);
|
||||
|
||||
@ -211,6 +222,22 @@ private:
|
||||
void DispatchGestureEvent(PRUint32 msg, PRUint32 direction, double delta,
|
||||
const nsIntPoint &refPoint, PRUint64 time);
|
||||
void HandleSpecialKey(mozilla::AndroidGeckoEvent *ae);
|
||||
void RedrawAll();
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
nsRefPtr<nsAccessible> mRootAccessible;
|
||||
|
||||
/**
|
||||
* Request to create the accessible for this window if it is top level.
|
||||
*/
|
||||
void CreateRootAccessible();
|
||||
|
||||
/**
|
||||
* Generate the NS_GETACCESSIBLE event to get accessible for this window
|
||||
* and return it.
|
||||
*/
|
||||
nsAccessible *DispatchAccessibleEvent();
|
||||
#endif // ACCESSIBILITY
|
||||
};
|
||||
|
||||
#endif /* NSWINDOW_H_ */
|
||||
|
@ -53,6 +53,10 @@
|
||||
#include "nsConsoleMessage.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsConsoleService)
|
||||
@ -135,6 +139,16 @@ nsConsoleService::LogMessage(nsIConsoleMessage *message)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
#if defined(ANDROID)
|
||||
{
|
||||
nsXPIDLString msg;
|
||||
message->GetMessageMoz(getter_Copies(msg));
|
||||
__android_log_print(ANDROID_LOG_ERROR, "Gecko *** Console Service *** ",
|
||||
"%s",
|
||||
NS_LossyConvertUTF16toASCII(msg).get());
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If there's already a message in the slot we're about to replace,
|
||||
* we've wrapped around, and we need to release the old message. We
|
||||
|
Loading…
Reference in New Issue
Block a user