diff options
author | Pale Moon <git-repo@palemoon.org> | 2016-09-01 13:39:08 +0200 |
---|---|---|
committer | Pale Moon <git-repo@palemoon.org> | 2016-09-01 13:39:08 +0200 |
commit | 3d8ce1a11a7347cc94a937719c4bc8df46fb8d14 (patch) | |
tree | 8c26ca375a6312751c00a27e1653fb6f189f0463 /dom/activities | |
parent | e449bdb1ec3a82f204bffdd9c3c54069d086eee3 (diff) | |
download | palemoon-gre-3d8ce1a11a7347cc94a937719c4bc8df46fb8d14.tar.gz |
Base import of Tycho code (warning: huge commit)
Diffstat (limited to 'dom/activities')
25 files changed, 463 insertions, 411 deletions
diff --git a/dom/activities/src/Activities.manifest b/dom/activities/Activities.manifest index 67a17ae1e..06b14cdc6 100644 --- a/dom/activities/src/Activities.manifest +++ b/dom/activities/Activities.manifest @@ -4,8 +4,8 @@ contract @mozilla.org/dom/activities/proxy;1 {ba9bd5cb-76a0-4ecf-a7b3-d2f7c43c59 component {5430d6f9-32d6-4924-ba39-6b6d1b093cd6} ActivityWrapper.js contract @mozilla.org/dom/system-messages/wrapper/activity;1 {5430d6f9-32d6-4924-ba39-6b6d1b093cd6} +component {d2296daa-c406-4c5e-b698-e5f2c1715798} ActivityMessageConfigurator.js +contract @mozilla.org/dom/system-messages/configurator/activity;1 {d2296daa-c406-4c5e-b698-e5f2c1715798} + component {9326952a-dbe3-4d81-a51f-d9c160d96d6b} ActivityRequestHandler.js contract @mozilla.org/dom/activities/request-handler;1 {9326952a-dbe3-4d81-a51f-d9c160d96d6b} - -component {ee983dbb-d5ea-4c5b-be98-10a13cac9f9d} ActivityOptions.js -contract @mozilla.org/dom/activities/options;1 {ee983dbb-d5ea-4c5b-be98-10a13cac9f9d} diff --git a/dom/activities/src/ActivitiesService.jsm b/dom/activities/ActivitiesService.jsm index 8ff9bf34f..f442e57fd 100644 --- a/dom/activities/src/ActivitiesService.jsm +++ b/dom/activities/ActivitiesService.jsm @@ -11,15 +11,23 @@ const Ci = Components.interfaces; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/IndexedDBHelper.jsm"); -Cu.import("resource://gre/modules/ActivitiesServiceFilter.jsm"); +Cu.import("resource://gre/modules/AppsUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "DOMApplicationRegistry", + "resource://gre/modules/Webapps.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "ActivitiesServiceFilter", + "resource://gre/modules/ActivitiesServiceFilter.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "ppmm", "@mozilla.org/parentprocessmessagemanager;1", "nsIMessageBroadcaster"); -this.EXPORTED_SYMBOLS = []; +XPCOMUtils.defineLazyServiceGetter(this, "NetUtil", + "@mozilla.org/network/util;1", + "nsINetUtil"); -let idbGlobal = this; +this.EXPORTED_SYMBOLS = []; function debug(aMsg) { //dump("-- ActivitiesService.jsm " + Date.now() + " " + aMsg + "\n"); @@ -37,10 +45,7 @@ ActivitiesDb.prototype = { __proto__: IndexedDBHelper.prototype, init: function actdb_init() { - let idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"] - .getService(Ci.nsIIndexedDatabaseManager); - idbManager.initWindowless(idbGlobal); - this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME], idbGlobal); + this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME]); }, /** @@ -117,6 +122,20 @@ ActivitiesDb.prototype = { }.bind(this), function() {}, function() {}); }, + // Remove all activities associated with the given |aManifest| URL. + removeAll: function actdb_removeAll(aManifest) { + this.newTxn("readwrite", STORE_NAME, function (txn, store) { + let index = store.index("manifest"); + let request = index.mozGetAll(aManifest); + request.onsuccess = function manifestActivities(aEvent) { + aEvent.target.result.forEach(function(result) { + debug('Removing activity: ' + JSON.stringify(result)); + store.delete(result.id); + }); + }; + }); + }, + find: function actdb_find(aObject, aSuccess, aError, aMatch) { debug("Looking for " + aObject.options.name); @@ -152,12 +171,19 @@ let Activities = { // ActivityProxy.js "Activity:Start", + // ActivityWrapper.js + "Activity:Ready", + // ActivityRequestHandler.js "Activity:PostResult", "Activity:PostError", "Activities:Register", "Activities:Unregister", + "Activities:UnregisterAll", + "Activities:GetContentTypes", + + "child-process-shutdown" ], init: function activities_init() { @@ -196,63 +222,125 @@ let Activities = { startActivity: function activities_startActivity(aMsg) { debug("StartActivity: " + JSON.stringify(aMsg)); + // The caller app will be killed by |assertAppHasStatus| if it doesn't + // fit our permission requirement. + let callerApp = this.callers[aMsg.id].mm; + if (aMsg.options.name === 'internal-system-engineering-mode' && + !callerApp.assertAppHasStatus(Ci.nsIPrincipal.APP_STATUS_CERTIFIED)) { + return; + } + + let self = this; let successCb = function successCb(aResults) { debug(JSON.stringify(aResults)); - // We have no matching activity registered, let's fire an error. - if (aResults.options.length === 0) { - Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", { - "id": aMsg.id, - "error": "NO_PROVIDER" - }); - delete Activities.callers[aMsg.id]; - return; - } - - function getActivityChoice(aChoice) { - debug("Activity choice: " + aChoice); - - // The user has cancelled the choice, fire an error. - if (aChoice === -1) { - Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", { - "id": aMsg.id, - "error": "USER_ABORT" - }); - delete Activities.callers[aMsg.id]; - return; + function getActivityChoice(aResultType, aResult) { + switch(aResultType) { + case Ci.nsIActivityUIGlueCallback.NATIVE_ACTIVITY: { + self.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", { + "id": aMsg.id, + "result": aResult + }); + break; + } + case Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY: { + debug("Activity choice: " + aResult); + + // We have no matching activity registered, let's fire an error. + // Don't do this check until we have passed to UIGlue so the glue can choose to launch + // its own activity if needed. + if (aResults.options.length === 0) { + self.trySendAndCleanup(aMsg.id, "Activity:FireError", { + "id": aMsg.id, + "error": "NO_PROVIDER" + }); + return; + } + + // The user has cancelled the choice, fire an error. + if (aResult === -1) { + self.trySendAndCleanup(aMsg.id, "Activity:FireError", { + "id": aMsg.id, + "error": "ActivityCanceled" + }); + return; + } + + let sysmm = Cc["@mozilla.org/system-message-internal;1"] + .getService(Ci.nsISystemMessagesInternal); + if (!sysmm) { + // System message is not present, what should we do? + delete self.callers[aMsg.id]; + return; + } + + debug("Sending system message..."); + let result = aResults.options[aResult]; + sysmm.sendMessage("activity", { + "id": aMsg.id, + "payload": aMsg.options, + "target": result.description + }, + Services.io.newURI(result.description.href, null, null), + Services.io.newURI(result.manifest, null, null), + { + "manifestURL": self.callers[aMsg.id].manifestURL, + "pageURL": self.callers[aMsg.id].pageURL + }); + + if (!result.description.returnValue) { + // No need to notify observers, since we don't want the caller + // to be raised on the foreground that quick. + self.trySendAndCleanup(aMsg.id, "Activity:FireSuccess", { + "id": aMsg.id, + "result": null + }); + } + break; + } } + }; - let sysmm = Cc["@mozilla.org/system-message-internal;1"] - .getService(Ci.nsISystemMessagesInternal); - if (!sysmm) { - // System message is not present, what should we do? - return; - } + let caller = Activities.callers[aMsg.id]; + if (aMsg.getFilterResults === true && + caller.mm.assertAppHasStatus(Ci.nsIPrincipal.APP_STATUS_CERTIFIED)) { + // Certified apps can ask to just get the picker data. - debug("Sending system message..."); - let result = aResults.options[aChoice]; - sysmm.sendMessage("activity", { - "id": aMsg.id, - "payload": aMsg.options, - "target": result.description - }, - Services.io.newURI(result.description.href, null, null), - Services.io.newURI(result.manifest, null, null)); + // We want to return the manifest url, icon url and app name. + // The app name needs to be picked up from the localized manifest. + let reg = DOMApplicationRegistry; + let ids = aResults.options.map((aItem) => { + return { id: reg._appIdForManifestURL(aItem.manifest) } + }); - if (!result.description.returnValue) { - Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", { - "id": aMsg.id, - "result": null + reg._readManifests(ids).then((aManifests) => { + let results = []; + aManifests.forEach((aManifest, i) => { + let manifestURL = aResults.options[i].manifest; + // Not passing the origin is fine here since we only need + // helper.name which doesn't rely on url resolution. + let helper = + new ManifestHelper(aManifest.manifest, manifestURL, manifestURL); + results.push({ + manifestURL: manifestURL, + iconURL: aResults.options[i].icon, + appName: helper.name + }); }); - // No need to notify observers, since we don't want the caller - // to be raised on the foreground that quick. - delete Activities.callers[aMsg.id]; - } - }; - let glue = Cc["@mozilla.org/dom/activities/ui-glue;1"] - .createInstance(Ci.nsIActivityUIGlue); - glue.chooseActivity(aResults.name, aResults.options, getActivityChoice); + // Now fire success with the array of choices. + caller.mm.sendAsyncMessage("Activity:FireSuccess", + { + "id": aMsg.id, + "result": results + }); + delete Activities.callers[aMsg.id]; + }); + } else { + let glue = Cc["@mozilla.org/dom/activities/ui-glue;1"] + .createInstance(Ci.nsIActivityUIGlue); + glue.chooseActivity(aMsg.options, aResults.options, getActivityChoice); + } }; let errorCb = function errorCb(aError) { @@ -261,6 +349,12 @@ let Activities = { }; let matchFunc = function matchFunc(aResult) { + let calleeApp = DOMApplicationRegistry.getAppByManifestURL(aResult.manifest); + // Only allow certified apps to handle this special activity + if (aMsg.options.name === 'internal-system-engineering-mode' && + calleeApp.appStatus !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED) { + return false; + } return ActivitiesServiceFilter.match(aMsg.options.data, aResult.description.filters); }; @@ -268,6 +362,14 @@ let Activities = { this.db.find(aMsg, successCb, errorCb, matchFunc); }, + trySendAndCleanup: function activities_trySendAndCleanup(aId, aName, aPayload) { + try { + this.callers[aId].mm.sendAsyncMessage(aName, aPayload); + } finally { + delete this.callers[aId]; + } + }, + receiveMessage: function activities_receiveMessage(aMessage) { let mm = aMessage.target; let msg = aMessage.json; @@ -276,7 +378,8 @@ let Activities = { let obsData; if (aMessage.name == "Activity:PostResult" || - aMessage.name == "Activity:PostError") { + aMessage.name == "Activity:PostError" || + aMessage.name == "Activity:Ready") { caller = this.callers[msg.id]; if (!caller) { debug("!! caller is null for msg.id=" + msg.id); @@ -289,24 +392,25 @@ let Activities = { switch(aMessage.name) { case "Activity:Start": - this.callers[msg.id] = { mm: aMessage.target, + this.callers[msg.id] = { mm: mm, manifestURL: msg.manifestURL, pageURL: msg.pageURL }; this.startActivity(msg); break; + case "Activity:Ready": + caller.childMM = mm; + break; + case "Activity:PostResult": - caller.mm.sendAsyncMessage("Activity:FireSuccess", msg); - Services.obs.notifyObservers(null, "activity-done", obsData); - delete this.callers[msg.id]; + this.trySendAndCleanup(msg.id, "Activity:FireSuccess", msg); break; case "Activity:PostError": - caller.mm.sendAsyncMessage("Activity:FireError", msg); - Services.obs.notifyObservers(null, "activity-done", obsData); - delete this.callers[msg.id]; + this.trySendAndCleanup(msg.id, "Activity:FireError", msg); break; case "Activities:Register": + let self = this; this.db.add(msg, function onSuccess(aEvent) { mm.sendAsyncMessage("Activities:Register:OK", null); @@ -319,8 +423,23 @@ let Activities = { case "Activities:Unregister": this.db.remove(msg); break; + case "Activities:UnregisterAll": + this.db.removeAll(msg); + break; + case "child-process-shutdown": + for (let id in this.callers) { + if (this.callers[id].childMM == mm) { + this.trySendAndCleanup(id, "Activity:FireError", { + "id": id, + "error": "ActivityCanceled" + }); + break; + } + } + break; } } + } Activities.init(); diff --git a/dom/activities/src/ActivitiesServiceFilter.jsm b/dom/activities/ActivitiesServiceFilter.jsm index 73da892e5..8053ec458 100644 --- a/dom/activities/src/ActivitiesServiceFilter.jsm +++ b/dom/activities/ActivitiesServiceFilter.jsm @@ -105,6 +105,10 @@ this.ActivitiesServiceFilter = { continue; } + if (Array.isArray(aValues[prop]) && aValues[prop].length == 0) { + continue; + } + // Otherwise, let's check the value against the filter. if (!matchObject(aValues[prop], filtersMap[prop].filter)) { return false; diff --git a/dom/activities/src/Activity.cpp b/dom/activities/Activity.cpp index b51c113b7..12f246f10 100644 --- a/dom/activities/src/Activity.cpp +++ b/dom/activities/Activity.cpp @@ -3,8 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "Activity.h" - -#include "mozilla/dom/MozActivityBinding.h" +#include "mozilla/dom/ToJSValue.h" #include "nsContentUtils.h" #include "nsDOMClassInfo.h" #include "nsIConsoleService.h" @@ -19,33 +18,29 @@ NS_INTERFACE_MAP_END_INHERITING(DOMRequest) NS_IMPL_ADDREF_INHERITED(Activity, DOMRequest) NS_IMPL_RELEASE_INHERITED(Activity, DOMRequest) -NS_IMPL_CYCLE_COLLECTION_INHERITED_1(Activity, DOMRequest, - mProxy) +NS_IMPL_CYCLE_COLLECTION_INHERITED(Activity, DOMRequest, + mProxy) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Activity, DOMRequest) NS_IMPL_CYCLE_COLLECTION_TRACE_END /* virtual */ JSObject* -Activity::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) +Activity::WrapObject(JSContext* aCx) { - return MozActivityBinding::Wrap(aCx, aScope, this); + return MozActivityBinding::Wrap(aCx, this); } nsresult -Activity::Initialize(nsISupports* aOwner, - nsIDOMMozActivityOptions* aOptions) +Activity::Initialize(nsPIDOMWindow* aWindow, + JSContext* aCx, + const ActivityOptions& aOptions) { - MOZ_ASSERT(aOptions); - - nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aOwner); - NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED); - - Init(window); + MOZ_ASSERT(aWindow); - nsCOMPtr<nsIDocument> document = window->GetExtantDoc(); + nsCOMPtr<nsIDocument> document = aWindow->GetExtantDoc(); bool isActive; - window->GetDocShell()->GetIsActive(&isActive); + aWindow->GetDocShell()->GetIsActive(&isActive); if (!isActive && !nsContentUtils::IsChromeDoc(document)) { @@ -59,7 +54,7 @@ Activity::Initialize(nsISupports* aOwner, NS_ENSURE_TRUE(console, NS_OK); nsString message = - NS_LITERAL_STRING("Can start activity from non user input or chrome code"); + NS_LITERAL_STRING("Can only start activity from user input or chrome code"); console->LogStringMessage(message.get()); return NS_OK; @@ -71,7 +66,12 @@ Activity::Initialize(nsISupports* aOwner, mProxy = do_CreateInstance("@mozilla.org/dom/activities/proxy;1", &rv); NS_ENSURE_SUCCESS(rv, rv); - mProxy->StartActivity(static_cast<nsIDOMDOMRequest*>(this), aOptions, window); + JS::Rooted<JS::Value> optionsValue(aCx); + if (!ToJSValue(aCx, aOptions, &optionsValue)) { + return NS_ERROR_FAILURE; + } + + mProxy->StartActivity(static_cast<nsIDOMDOMRequest*>(this), optionsValue, aWindow); return NS_OK; } @@ -82,12 +82,8 @@ Activity::~Activity() } } -Activity::Activity() - : DOMRequest() +Activity::Activity(nsPIDOMWindow* aWindow) + : DOMRequest(aWindow) { - // Unfortunately we must explicitly declare the default constructor in order - // to prevent an implicitly deleted constructor in DOMRequest compile error - // in GCC 4.6. - MOZ_ASSERT(IsDOMBinding()); } diff --git a/dom/activities/src/Activity.h b/dom/activities/Activity.h index 4626e8347..f7c990573 100644 --- a/dom/activities/src/Activity.h +++ b/dom/activities/Activity.h @@ -7,13 +7,10 @@ #include "DOMRequest.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/MozActivityBinding.h" #include "nsIActivityProxy.h" #include "mozilla/Preferences.h" - -#define NS_DOMACTIVITY_CID \ - {0x1c5b0930, 0xc90c, 0x4e9c, {0xaf, 0x4e, 0xb0, 0xb7, 0xa6, 0x59, 0xb4, 0xed}} - -#define NS_DOMACTIVITY_CONTRACTID "@mozilla.org/dom/activity;1" +#include "nsPIDOMWindow.h" namespace mozilla { namespace dom { @@ -24,29 +21,30 @@ public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(Activity, DOMRequest) - virtual JSObject* WrapObject(JSContext* aCx, - JS::Handle<JSObject*> aScope) MOZ_OVERRIDE; - - static bool PrefEnabled() - { - return Preferences::GetBool("dom.sysmsg.enabled", false); - } + virtual JSObject* WrapObject(JSContext* aCx) override; static already_AddRefed<Activity> Constructor(const GlobalObject& aOwner, - nsIDOMMozActivityOptions* aOptions, + const ActivityOptions& aOptions, ErrorResult& aRv) { - nsRefPtr<Activity> activity = new Activity(); - aRv = activity->Initialize(aOwner.Get(), aOptions); + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aOwner.GetAsSupports()); + if (!window) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsRefPtr<Activity> activity = new Activity(window); + aRv = activity->Initialize(window, aOwner.Context(), aOptions); return activity.forget(); } - Activity(); + explicit Activity(nsPIDOMWindow* aWindow); protected: - nsresult Initialize(nsISupports* aOwner, - nsIDOMMozActivityOptions* aOptions); + nsresult Initialize(nsPIDOMWindow* aWindow, + JSContext* aCx, + const ActivityOptions& aOptions); nsCOMPtr<nsIActivityProxy> mProxy; diff --git a/dom/activities/ActivityMessageConfigurator.js b/dom/activities/ActivityMessageConfigurator.js new file mode 100644 index 000000000..c0c358c13 --- /dev/null +++ b/dom/activities/ActivityMessageConfigurator.js @@ -0,0 +1,33 @@ +/* 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/. */ + +"use strict"; + +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +function debug(aMsg) { + // dump("-- ActivityMessageConfigurator.js " + Date.now() + " : " + aMsg + "\n"); +} + +/** + * nsISystemMessagesConfigurator implementation. + */ +function ActivityMessageConfigurator() { + debug("ActivityMessageConfigurator"); +} + +ActivityMessageConfigurator.prototype = { + get mustShowRunningApp() { + debug("mustShowRunningApp returning true"); + return true; + }, + + classID: Components.ID("{d2296daa-c406-4c5e-b698-e5f2c1715798}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesConfigurator]) +} + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityMessageConfigurator]); diff --git a/dom/activities/src/ActivityProxy.js b/dom/activities/ActivityProxy.js index f38a99e4f..560ee798b 100644 --- a/dom/activities/src/ActivityProxy.js +++ b/dom/activities/ActivityProxy.js @@ -10,7 +10,6 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/ObjectWrapper.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "cpmm", "@mozilla.org/childprocessmessagemanager;1", @@ -53,16 +52,36 @@ ActivityProxy.prototype = { appId != Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) ? DOMApplicationRegistry.getManifestURLByLocalId(appId) : null; - cpmm.sendAsyncMessage("Activity:Start", { id: this.id, - options: { - name: aOptions.name, - data: aOptions.data - }, - manifestURL: manifestURL, - pageURL: aWindow.document.location.href }); + + // Only let certified apps enumerate providers for this filter. + if (aOptions.getFilterResults === true && + principal.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED) { + Services.DOMRequest.fireErrorAsync(this.activity, "SecurityError"); + Services.obs.notifyObservers(null, "Activity:Error", null); + return; + } + + // Only let certified app to initiate this activitiy. + if (aOptions.name === 'internal-system-engineering-mode' && + principal.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED) { + Services.DOMRequest.fireErrorAsync(this.activity, "SecurityError"); + Services.obs.notifyObservers(null, "Activity:Error", null); + return; + } cpmm.addMessageListener("Activity:FireSuccess", this); cpmm.addMessageListener("Activity:FireError", this); + + cpmm.sendAsyncMessage("Activity:Start", + { + id: this.id, + options: { + name: aOptions.name, + data: aOptions.data + }, + getFilterResults: aOptions.getFilterResults, + manifestURL: manifestURL, + pageURL: aWindow.document.location.href }); }, receiveMessage: function actProxy_receiveMessage(aMessage) { @@ -76,11 +95,13 @@ ActivityProxy.prototype = { case "Activity:FireSuccess": debug("FireSuccess"); Services.DOMRequest.fireSuccess(this.activity, - ObjectWrapper.wrap(msg.result, this.window)); + Cu.cloneInto(msg.result, this.window)); + Services.obs.notifyObservers(null, "Activity:Success", null); break; case "Activity:FireError": debug("FireError"); Services.DOMRequest.fireError(this.activity, msg.error); + Services.obs.notifyObservers(null, "Activity:Error", null); break; } // We can only get one FireSuccess / FireError message, so cleanup as soon as possible. @@ -89,7 +110,7 @@ ActivityProxy.prototype = { cleanup: function actProxy_cleanup() { debug("cleanup"); - if (!this.cleanedUp) { + if (cpmm && !this.cleanedUp) { cpmm.removeMessageListener("Activity:FireSuccess", this); cpmm.removeMessageListener("Activity:FireError", this); } diff --git a/dom/activities/src/ActivityRequestHandler.js b/dom/activities/ActivityRequestHandler.js index 3bc143624..ffe1504eb 100644 --- a/dom/activities/src/ActivityRequestHandler.js +++ b/dom/activities/ActivityRequestHandler.js @@ -4,11 +4,11 @@ "use strict"; -const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "cpmm", "@mozilla.org/childprocessmessagemanager;1", @@ -24,28 +24,28 @@ function debug(aMsg) { function ActivityRequestHandler() { debug("ActivityRequestHandler"); - this.wrappedJSObject = this; // When a system message of type 'activity' is emitted, it forces the // creation of an ActivityWrapper which in turns replace the default - // system message callback. The newly created wrapper then create a - // nsIDOMActivityRequestHandler object and fills up the properties of - // this object as well as the properties of the nsIDOMActivityOptions - // object contains by the request handler. - this._id = null; - this._options = Cc["@mozilla.org/dom/activities/options;1"] - .createInstance(Ci.nsIDOMMozActivityOptions); + // system message callback. The newly created wrapper then create an + // ActivityRequestHandler object. } ActivityRequestHandler.prototype = { - __exposedProps__: { - source: "r", - postResult: "r", - postError: "r" - }, + init: function arh_init(aWindow) { + this._window = aWindow; + }, + + __init: function arh___init(aId, aOptions) { + this._id = aId; + this._options = aOptions; + }, get source() { - return this._options; + // We need to clone this object because the this._options.data has + // the type any in WebIDL which will cause the binding layer to pass + // the value which is a COW unmodified to content. + return Cu.cloneInto(this._options, this._window); }, postResult: function arh_postResult(aResult) { @@ -53,6 +53,7 @@ ActivityRequestHandler.prototype = { "id": this._id, "result": aResult }); + Services.obs.notifyObservers(null, "activity-success", this._id); }, postError: function arh_postError(aError) { @@ -60,21 +61,14 @@ ActivityRequestHandler.prototype = { "id": this._id, "error": aError }); + Services.obs.notifyObservers(null, "activity-error", this._id); }, classID: Components.ID("{9326952a-dbe3-4d81-a51f-d9c160d96d6b}"), QueryInterface: XPCOMUtils.generateQI([ - Ci.nsIDOMMozActivityRequestHandler - ]), - - classInfo: XPCOMUtils.generateCI({ - classID: Components.ID("{9326952a-dbe3-4d81-a51f-d9c160d96d6b}"), - contractID: "@mozilla.org/dom/activities/request-handler;1", - interfaces: [Ci.nsIDOMMozActivityRequestHandler], - flags: Ci.nsIClassInfo.DOM_OBJECT, - classDescription: "Activity Request Handler" - }) + Ci.nsIDOMGlobalPropertyInitializer + ]) } this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityRequestHandler]); diff --git a/dom/activities/ActivityWrapper.js b/dom/activities/ActivityWrapper.js new file mode 100644 index 000000000..a9e81c428 --- /dev/null +++ b/dom/activities/ActivityWrapper.js @@ -0,0 +1,91 @@ +/* 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/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "cpmm", + "@mozilla.org/childprocessmessagemanager;1", + "nsISyncMessageSender"); + +function debug(aMsg) { + //dump("-- ActivityWrapper.js " + Date.now() + " : " + aMsg + "\n"); +} + +/** + * nsISystemMessagesWrapper implementation. Will return a + * nsIDOMMozActivityRequestHandler + */ +function ActivityWrapper() { + debug("ActivityWrapper"); +} + +ActivityWrapper.prototype = { + wrapMessage: function wrapMessage(aMessage, aWindow) { + debug("Wrapping " + JSON.stringify(aMessage)); + + // This message is useful to communicate that the activity message has been + // properly received by the app. If the app will be killed, the + // ActivitiesService will be able to fire an error and complete the + // Activity workflow. + cpmm.sendAsyncMessage("Activity:Ready", { id: aMessage.id }); + + let handler = new aWindow.ActivityRequestHandler(aMessage.id, aMessage.payload); + + // When the activity window is closed, fire an error to notify the activity + // caller of the situation. + // We don't need to check whether the activity itself already sent + // back something since ActivitiesService.jsm takes care of that. + let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + let innerWindowID = util.currentInnerWindowID; + + let observer = { + observe: function(aSubject, aTopic, aData) { + + switch (aTopic) { + case 'inner-window-destroyed': + let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data; + if (wId == innerWindowID) { + debug("Closing activity window " + innerWindowID); + Services.obs.removeObserver(observer, "inner-window-destroyed"); + cpmm.sendAsyncMessage("Activity:PostError", + { id: aMessage.id, + error: "ActivityCanceled" + }); + } + break; + case 'activity-error': + case 'activity-success': + if (aData !== aMessage.id) { + return; + } + Services.obs.removeObserver(observer, "activity-error"); + Services.obs.removeObserver(observer, "activity-success"); + let docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation); + Services.obs.notifyObservers(docshell, "activity-done", aTopic); + break; + } + } + } + + Services.obs.addObserver(observer, "activity-error", false); + Services.obs.addObserver(observer, "activity-success", false); + Services.obs.addObserver(observer, "inner-window-destroyed", false); + return handler; + }, + + classID: Components.ID("{5430d6f9-32d6-4924-ba39-6b6d1b093cd6}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesWrapper]) +} + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityWrapper]); + diff --git a/dom/activities/interfaces/moz.build b/dom/activities/interfaces/moz.build index e60db2345..0e7a25704 100644 --- a/dom/activities/interfaces/moz.build +++ b/dom/activities/interfaces/moz.build @@ -7,17 +7,7 @@ XPIDL_SOURCES += [ 'nsIActivityProxy.idl', 'nsIActivityUIGlue.idl', - 'nsIDOMActivityHandlerDescription.idl', - 'nsIDOMActivityOptions.idl', - 'nsIDOMActivityRequestHandler.idl', - 'nsIDOMNavigatorActivities.idl', ] XPIDL_MODULE = 'dom_activities' -XPIDL_FLAGS += [ - '-I$(topsrcdir)/dom/base', - '-I$(topsrcdir)/dom/interfaces/base', - '-I$(topsrcdir)/dom/interfaces/events', -] - diff --git a/dom/activities/interfaces/nsIActivityProxy.idl b/dom/activities/interfaces/nsIActivityProxy.idl index 680971073..ddf450127 100644 --- a/dom/activities/interfaces/nsIActivityProxy.idl +++ b/dom/activities/interfaces/nsIActivityProxy.idl @@ -4,17 +4,16 @@ #include "nsISupports.idl" -interface nsIDOMMozActivityOptions; interface nsIDOMWindow; /** * Implemented by @mozilla.org/dom/activities/proxy;1 */ -[scriptable, uuid(c7a258f7-26a6-46c6-a887-a6c936034f98)] +[scriptable, uuid(60adef0f-c1a7-4dc5-bc0d-4b879f1e59ca)] interface nsIActivityProxy : nsISupports { void startActivity(in nsISupports /* MozActivity */ activity, - in nsIDOMMozActivityOptions options, + in jsval options, in nsIDOMWindow window); void cleanup(); }; diff --git a/dom/activities/interfaces/nsIActivityUIGlue.idl b/dom/activities/interfaces/nsIActivityUIGlue.idl index 3bc15e45b..8e3a4751f 100644 --- a/dom/activities/interfaces/nsIActivityUIGlue.idl +++ b/dom/activities/interfaces/nsIActivityUIGlue.idl @@ -4,22 +4,42 @@ #include "nsISupports.idl" -[scriptable, function, uuid(7a16feb4-5a78-4589-9174-b728f26942e2)] +[scriptable, function, uuid(674b6e69-05f0-41da-aabd-4184ea85c9d8)] interface nsIActivityUIGlueCallback : nsISupports { - void handleEvent(in long choice); + /** + * The activity service should start the activity at the specified index. + */ + const short WEBAPPS_ACTIVITY = 0; + + /** + * The activity service should deliver the specified result to the MozActivity callback. + */ + const short NATIVE_ACTIVITY = 1; + + /** + * Called if the user picked an activitiy to launch. + * @param resultType Inidcates that {@code result} is an index or a native activity result. + * @param result If WEBAPPS_ACTIVITY, the index of the chosen activity. Send '-1' if no choice is made. + If NATIVE_ACTIVITY, the return value to be sent to the MozActivity. + */ + void handleEvent(in short resultType, in jsval result); }; /** * To be implemented by @mozilla.org/dom/activities/ui-glue;1 */ -[scriptable, uuid(8624ad73-937a-400f-9d93-39ab5449b867)] +[scriptable, uuid(3caef69f-3569-4b19-bcea-1cfb0fee4466)] interface nsIActivityUIGlue : nsISupports { /** - * @param name The name of the activity to handle (eg. "share", "pick"). + * This method is called even if the size of {@code activities} is 0 so that the callee can + * decide whether or not to defer the request to an alternate activity system. + * + * @param options The ActivityOptions object in the form of { name: "send", data: { ... } } * @param activities A json blob which is an array of { "title":"...", "icon":"..." }. - * @param onresult The callback to send the index of the choosen activity. Send -1 if no choice is made. + * @param callback The callback to send the index of the choosen activity, or the result. */ - void chooseActivity(in DOMString title, in jsval activities, in nsIActivityUIGlueCallback onresult); + void chooseActivity(in jsval options, in jsval activities, + in nsIActivityUIGlueCallback callback); }; diff --git a/dom/activities/interfaces/nsIDOMActivityHandlerDescription.idl b/dom/activities/interfaces/nsIDOMActivityHandlerDescription.idl deleted file mode 100644 index 7e8680df4..000000000 --- a/dom/activities/interfaces/nsIDOMActivityHandlerDescription.idl +++ /dev/null @@ -1,19 +0,0 @@ -/* 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/. */ - -#include "domstubs.idl" - -/** - * The constructor will accept the name as a parameter. - */ -[scriptable, uuid(1601d370-08d9-47b7-8802-d4291533b843)] -interface nsIDOMMozActivityHandlerDescription : nsISupports -{ - attribute DOMString name; - attribute DOMString href; - attribute DOMString disposition; - attribute boolean returnValue; - // The |filters| property can be null. - attribute jsval filters; -}; diff --git a/dom/activities/interfaces/nsIDOMActivityOptions.idl b/dom/activities/interfaces/nsIDOMActivityOptions.idl deleted file mode 100644 index 146eb43e3..000000000 --- a/dom/activities/interfaces/nsIDOMActivityOptions.idl +++ /dev/null @@ -1,13 +0,0 @@ -/* 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/. */ - -#include "domstubs.idl" - -[scriptable, uuid(f5bf5e9b-f53f-470f-b560-0d6f4c1c98ad)] -interface nsIDOMMozActivityOptions : nsISupports -{ - readonly attribute DOMString name; - // The |data| field can be null. - readonly attribute jsval data; -}; diff --git a/dom/activities/interfaces/nsIDOMActivityRequestHandler.idl b/dom/activities/interfaces/nsIDOMActivityRequestHandler.idl deleted file mode 100644 index 5cea23688..000000000 --- a/dom/activities/interfaces/nsIDOMActivityRequestHandler.idl +++ /dev/null @@ -1,15 +0,0 @@ -/* 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/. */ - -#include "domstubs.idl" - -interface nsIDOMMozActivityOptions; - -[scriptable, uuid(e70c4181-ea3f-4aa5-a2f7-af910dc65e45)] -interface nsIDOMMozActivityRequestHandler : nsISupports -{ - void postResult(in jsval result); - void postError(in DOMString error); - readonly attribute nsIDOMMozActivityOptions source; -}; diff --git a/dom/activities/interfaces/nsIDOMNavigatorActivities.idl b/dom/activities/interfaces/nsIDOMNavigatorActivities.idl deleted file mode 100644 index cf5f7e865..000000000 --- a/dom/activities/interfaces/nsIDOMNavigatorActivities.idl +++ /dev/null @@ -1,20 +0,0 @@ -/* 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/. */ - -#include "domstubs.idl" - -interface nsIDOMMozActivityHandlerDescription; -interface nsIDOMDOMRequest; - -/** - * This interface is implemented by the Navigator object. - */ -[scriptable, uuid(e7cb7d2f-11d2-4783-a8b0-bddabb4a5c03)] -interface nsIDOMMozNavigatorActivities : nsISupports -{ - nsIDOMDOMRequest mozRegisterActivityHandler(in nsIDOMMozActivityHandlerDescription description); - void mozUnregisterActivityHandler(in nsIDOMMozActivityHandlerDescription description); - - bool mozIsActivityHandlerRegistered(in nsIDOMMozActivityHandlerDescription description); -}; diff --git a/dom/activities/moz.build b/dom/activities/moz.build index 80787537c..98a5601e3 100644 --- a/dom/activities/moz.build +++ b/dom/activities/moz.build @@ -4,6 +4,35 @@ # 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/. -PARALLEL_DIRS += ['interfaces', 'src'] +DIRS += ['interfaces'] -TEST_DIRS += ['tests'] +XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] + +EXPORTS.mozilla.dom += [ + 'Activity.h', +] + +SOURCES += [ + 'Activity.cpp', +] + +EXTRA_COMPONENTS += [ + 'Activities.manifest', + 'ActivityMessageConfigurator.js', + 'ActivityProxy.js', + 'ActivityRequestHandler.js', + 'ActivityWrapper.js', +] + +EXTRA_JS_MODULES += [ + 'ActivitiesService.jsm', + 'ActivitiesServiceFilter.jsm', +] + +FAIL_ON_WARNINGS = True + +LOCAL_INCLUDES += [ + '/dom/base', +] + +FINAL_LIBRARY = 'xul' diff --git a/dom/activities/src/ActivityOptions.js b/dom/activities/src/ActivityOptions.js deleted file mode 100644 index 6481266cb..000000000 --- a/dom/activities/src/ActivityOptions.js +++ /dev/null @@ -1,56 +0,0 @@ -/* 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/. */ - -"use strict"; - -const Ci = Components.interfaces; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -function debug(aMsg) { - //dump("-- ActivityOptions.js " + Date.now() + " : " + aMsg + "\n"); -} - -/** - * nsIDOMMozActivityOptions implementation. - */ - -function ActivityOptions() { - debug("ActivityOptions"); - this.wrappedJSObject = this; - - // When a system message of type 'activity' is emitted, it forces the - // creation of an ActivityWrapper which in turns replace the default - // system message callback. The newly created wrapper then create a - // nsIDOMActivityRequestHandler object and fills up the properties of - // this object as well as the properties of the nsIDOMActivityOptions - // object contains by the request handler. - this._name = null; - this._data = null; -} - -ActivityOptions.prototype = { - get name() { - return this._name; - }, - - get data() { - return this._data; - }, - - classID: Components.ID("{ee983dbb-d5ea-4c5b-be98-10a13cac9f9d}"), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozActivityOptions]), - - classInfo: XPCOMUtils.generateCI({ - classID: Components.ID("{ee983dbb-d5ea-4c5b-be98-10a13cac9f9d}"), - contractID: "@mozilla.org/dom/activities/options;1", - interfaces: [Ci.nsIDOMMozActivityOptions], - flags: Ci.nsIClassInfo.DOM_OBJECT, - classDescription: "Activity Options" - }) -} - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityOptions]); diff --git a/dom/activities/src/ActivityWrapper.js b/dom/activities/src/ActivityWrapper.js deleted file mode 100644 index 8cdc99846..000000000 --- a/dom/activities/src/ActivityWrapper.js +++ /dev/null @@ -1,46 +0,0 @@ -/* 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/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/ObjectWrapper.jsm"); - -function debug(aMsg) { - //dump("-- ActivityWrapper.js " + Date.now() + " : " + aMsg + "\n"); -} - -/** - * nsISystemMessagesWrapper implementation. Will return a - * nsIDOMMozActivityRequestHandler - */ -function ActivityWrapper() { - debug("ActivityWrapper"); -} - -ActivityWrapper.prototype = { - wrapMessage: function wrapMessage(aMessage, aWindow) { - debug("Wrapping " + JSON.stringify(aMessage)); - let handler = Cc["@mozilla.org/dom/activities/request-handler;1"] - .createInstance(Ci.nsIDOMMozActivityRequestHandler); - handler.wrappedJSObject._id = aMessage.id; - - // options is an nsIDOMActivityOptions object. - var options = handler.wrappedJSObject._options; - options.wrappedJSObject._name = aMessage.payload.name; - options.wrappedJSObject._data = ObjectWrapper.wrap(aMessage.payload.data, aWindow); - - return handler; - }, - - classID: Components.ID("{5430d6f9-32d6-4924-ba39-6b6d1b093cd6}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesWrapper]) -} - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityWrapper]); - diff --git a/dom/activities/src/Makefile.in b/dom/activities/src/Makefile.in deleted file mode 100644 index 0aba393ed..000000000 --- a/dom/activities/src/Makefile.in +++ /dev/null @@ -1,28 +0,0 @@ -# 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/. - -DEPTH = @DEPTH@ -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -LIBRARY_NAME = dom_activities_s -LIBXUL_LIBRARY = 1 -FORCE_STATIC_LIB = 1 -FAIL_ON_WARNINGS := 1 - -include $(topsrcdir)/dom/dom-config.mk - -DISABLED_EXTRA_COMPONENTS = \ - ActivityOptions.js \ - ActivityProxy.js \ - ActivityRequestHandler.js \ - ActivityWrapper.js \ - Activities.manifest \ - $(NULL) - -include $(topsrcdir)/config/config.mk -include $(topsrcdir)/config/rules.mk diff --git a/dom/activities/src/moz.build b/dom/activities/src/moz.build deleted file mode 100644 index edfba430e..000000000 --- a/dom/activities/src/moz.build +++ /dev/null @@ -1,28 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -MODULE = 'dom' - -EXPORTS.mozilla.dom += [ - 'Activity.h', -] - -CPP_SOURCES += [ - 'Activity.cpp', -] - -EXTRA_COMPONENTS += [ - 'Activities.manifest', - 'ActivityOptions.js', - 'ActivityProxy.js', - 'ActivityRequestHandler.js', - 'ActivityWrapper.js', -] - -EXTRA_JS_MODULES += [ - 'ActivitiesService.jsm', - 'ActivitiesServiceFilter.jsm', -] diff --git a/dom/activities/tests/Makefile.in b/dom/activities/tests/Makefile.in deleted file mode 100644 index e8a194c89..000000000 --- a/dom/activities/tests/Makefile.in +++ /dev/null @@ -1,15 +0,0 @@ -# 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/. - -DEPTH = @DEPTH@ -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ -relativesrcdir = @relativesrcdir@ - -FAIL_ON_WARNINGS := 1 - -include $(DEPTH)/config/autoconf.mk - -include $(topsrcdir)/config/rules.mk diff --git a/dom/activities/tests/moz.build b/dom/activities/tests/moz.build deleted file mode 100644 index 191c90f0b..000000000 --- a/dom/activities/tests/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini'] diff --git a/dom/activities/tests/unit/test_activityFilters.js b/dom/activities/tests/unit/test_activityFilters.js index d92d38aa0..95186eeb1 100644 --- a/dom/activities/tests/unit/test_activityFilters.js +++ b/dom/activities/tests/unit/test_activityFilters.js @@ -150,4 +150,8 @@ function run_test() { {a: { required: true, pattern: 'foobar'}})); do_check_true(ActivitiesServiceFilter.match({a: 'FoOBaR'}, {a: { required: true, pattern: 'foobar', patternFlags: 'i'}})); + + // Bug 923274 + do_check_true(ActivitiesServiceFilter.match({a:[]}, {a:'a'})); + do_check_false(ActivitiesServiceFilter.match({a:[]}, {a: { required: true, value: 'a'}})); } diff --git a/dom/activities/tests/unit/xpcshell.ini b/dom/activities/tests/unit/xpcshell.ini index d7aeee7af..6892190ab 100644 --- a/dom/activities/tests/unit/xpcshell.ini +++ b/dom/activities/tests/unit/xpcshell.ini @@ -1,5 +1,6 @@ [DEFAULT] head = tail = +skip-if = toolkit == 'gonk' [test_activityFilters.js] |