Bug 1284455 - Remove the Web Activities API r=me

MozReview-Commit-ID: 5SNGsRU4m9V

--HG--
extra : rebase_source : ccc6860481faa17b4b52571ae4fa6d9f2fc749de
This commit is contained in:
Fabrice Desré 2016-04-20 19:02:44 +02:00
parent 4b4d7ebc98
commit f3a986a379
37 changed files with 0 additions and 2142 deletions

View File

@ -8,7 +8,6 @@ window.performance.mark('gecko-shell-loadstart');
Cu.import('resource://gre/modules/ContactService.jsm');
Cu.import('resource://gre/modules/AlarmService.jsm');
Cu.import('resource://gre/modules/ActivitiesService.jsm');
Cu.import('resource://gre/modules/NotificationDB.jsm');
Cu.import('resource://gre/modules/Payment.jsm');
Cu.import("resource://gre/modules/AppsUtils.jsm");

View File

@ -1,91 +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/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");
function ActivitiesDialog() {
this._id = 0;
this.activities = [];
}
ActivitiesDialog.prototype = {
run: function ap_run() {
let id = "activity-choice" + this._id++;
let activity = this.activities.shift();
let choices = [];
activity.list.forEach(function(item) {
choices.push({ manifest: item.manifest, icon: item.icon });
});
// Keep up the frond-end of an activity choice. The messages contains
// a list of {names, icons} for applications able to handle this particular
// activity. The front-end should display a UI to pick one.
let detail = {
type: "activity-choice",
id: id,
name: activity.name,
choices: choices
};
if (activity.type) {
detail.activityType = activity.type;
}
// Listen the resulting choice from the front-end. If there is no choice,
// let's return -1, which means the user has cancelled the dialog.
SystemAppProxy.addEventListener("mozContentEvent", function act_getChoice(evt) {
if (evt.detail.id != id)
return;
SystemAppProxy.removeEventListener("mozContentEvent", act_getChoice);
activity.callback.handleEvent(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY,
evt.detail.value !== undefined
? evt.detail.value
: -1);
});
SystemAppProxy.dispatchEvent(detail);
},
chooseActivity: function ap_chooseActivity(aOptions, aActivities, aCallback) {
// B2G does not have an alternate activity system, make no choice and return.
if (aActivities.length === 0) {
aCallback.handleEvent(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY, -1);
return;
}
let activity = {
name: aOptions.name,
list: aActivities,
callback: aCallback
};
if (aOptions.data && aOptions.data.type) {
activity.type = aOptions.data.type;
}
this.activities.push(activity);
Services.tm.currentThread.dispatch(this, Ci.nsIEventTarget.DISPATCH_NORMAL);
},
classID: Components.ID("{3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIActivityUIGlue, Ci.nsIRunnable])
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivitiesDialog]);

View File

@ -23,10 +23,6 @@ contract @mozilla.org/b2g/directory-provider;1 {9181eb7c-6f87-11e1-90b1-4f59d80d
category xpcom-directory-providers b2g-directory-provider @mozilla.org/b2g/directory-provider;1
#endif
# ActivitiesGlue.js
component {3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e} ActivitiesGlue.js
contract @mozilla.org/dom/activities/ui-glue;1 {3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e}
# SystemMessageGlue.js
component {2846f034-e614-11e3-93cd-74d02b97e723} SystemMessageGlue.js
contract @mozilla.org/dom/messages/system-message-glue;1 {2846f034-e614-11e3-93cd-74d02b97e723}

View File

@ -7,7 +7,6 @@
DIRS += ['test']
EXTRA_COMPONENTS += [
'ActivitiesGlue.js',
'AlertsService.js',
'B2GAboutRedirector.js',
'B2GAppMigrator.js',

View File

@ -624,7 +624,6 @@
@RESPATH@/components/HCIEventTransactionSystemMessage.manifest
@RESPATH@/components/HCIEventTransactionSystemMessageConfigurator.js
@RESPATH@/components/Activities.manifest
@RESPATH@/components/ActivityProxy.js
@RESPATH@/components/ActivityRequestHandler.js
@RESPATH@/components/ActivityWrapper.js
@ -874,7 +873,6 @@ bin/libfreebl_32int64_3.so
#endif
@RESPATH@/components/WebappsUpdateTimer.js
@RESPATH@/components/DirectoryProvider.js
@RESPATH@/components/ActivitiesGlue.js
@RESPATH@/components/ProcessGlobal.js
@RESPATH@/components/OMAContentHandler.js
@RESPATH@/components/PaymentGlue.js

View File

@ -56,8 +56,6 @@ MOZ_APP_STATIC_INI=1
MOZ_WEBGL_CONFORMANT=1
# Enable navigator.mozPay
MOZ_PAY=1
# Enable activities. These are used for FxOS developers currently.
MOZ_ACTIVITIES=1
MOZ_JSDOWNLOADS=1
MOZ_RUST_MP4PARSE=1

View File

@ -175,10 +175,6 @@
@RESPATH@/components/directory.xpt
@RESPATH@/components/docshell.xpt
@RESPATH@/components/dom.xpt
#ifdef MOZ_ACTIVITIES
@RESPATH@/components/dom_activities.xpt
@RESPATH@/components/dom_messages.xpt
#endif
@RESPATH@/components/dom_apps.xpt
@RESPATH@/components/dom_newapps.xpt
@RESPATH@/components/dom_base.xpt
@ -537,19 +533,11 @@
@RESPATH@/components/TVSimulatorService.js
@RESPATH@/components/TVSimulatorService.manifest
#ifdef MOZ_ACTIVITIES
@RESPATH@/components/SystemMessageCache.js
@RESPATH@/components/SystemMessageInternal.js
@RESPATH@/components/SystemMessageManager.js
@RESPATH@/components/SystemMessageManager.manifest
@RESPATH@/components/Activities.manifest
@RESPATH@/components/ActivityProxy.js
@RESPATH@/components/ActivityRequestHandler.js
@RESPATH@/components/ActivityWrapper.js
@RESPATH@/components/ActivityMessageConfigurator.js
#endif
@RESPATH@/components/Payment.js
@RESPATH@/components/PaymentFlowInfo.js
@RESPATH@/components/Payment.manifest

View File

@ -1,11 +0,0 @@
component {ba9bd5cb-76a0-4ecf-a7b3-d2f7c43c5949} ActivityProxy.js
contract @mozilla.org/dom/activities/proxy;1 {ba9bd5cb-76a0-4ecf-a7b3-d2f7c43c5949}
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}

View File

@ -1,493 +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 Cu = Components.utils;
const Cc = Components.classes;
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/AppsUtils.jsm");
Cu.import("resource://gre/modules/AppConstants.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");
XPCOMUtils.defineLazyServiceGetter(this, "NetUtil",
"@mozilla.org/network/util;1",
"nsINetUtil");
this.EXPORTED_SYMBOLS = [];
function debug(aMsg) {
//dump("-- ActivitiesService.jsm " + Date.now() + " " + aMsg + "\n");
}
const DB_NAME = "activities";
const DB_VERSION = 2;
const STORE_NAME = "activities";
function ActivitiesDb() {
}
ActivitiesDb.prototype = {
__proto__: IndexedDBHelper.prototype,
init: function actdb_init() {
this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME]);
},
/**
* Create the initial database schema.
*
* The schema of records stored is as follows:
*
* {
* id: String
* manifest: String
* name: String
* icon: String
* description: jsval
* }
*/
upgradeSchema: function actdb_upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
debug("Upgrade schema " + aOldVersion + " -> " + aNewVersion);
let self = this;
/**
* WARNING!! Before upgrading the Activities DB take into account that an
* OTA unregisters all the activities and reinstalls them during the first
* run process. Check Bug 1193503.
*/
function upgrade(currentVersion) {
let next = upgrade.bind(self, currentVersion + 1);
switch (currentVersion) {
case 0:
self.createSchema(aDb, next);
break;
}
}
upgrade(aOldVersion);
},
createSchema: function(aDb, aNext) {
let objectStore = aDb.createObjectStore(STORE_NAME, { keyPath: "id" });
// indexes
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("manifest", "manifest", { unique: false });
debug("Created object stores and indexes");
aNext();
},
// unique ids made of (uri, action)
createId: function actdb_createId(aObject) {
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let hasher = Cc["@mozilla.org/security/hash;1"]
.createInstance(Ci.nsICryptoHash);
hasher.init(hasher.SHA1);
// add uri and action to the hash
["manifest", "name", "description"].forEach(function(aProp) {
if (!aObject[aProp]) {
return;
}
let property = aObject[aProp];
if (aProp == "description") {
property = JSON.stringify(aObject[aProp]);
}
let data = converter.convertToByteArray(property, {});
hasher.update(data, data.length);
});
return hasher.finish(true);
},
// Add all the activities carried in the |aObjects| array.
add: function actdb_add(aObjects, aSuccess, aError) {
this.newTxn("readwrite", STORE_NAME, function (txn, store) {
aObjects.forEach(function (aObject) {
let object = {
manifest: aObject.manifest,
name: aObject.name,
icon: aObject.icon || "",
description: aObject.description
};
object.id = this.createId(object);
debug("Going to add " + JSON.stringify(object));
store.put(object);
}, this);
}.bind(this), aSuccess, aError);
},
// Remove all the activities carried in the |aObjects| array.
remove: function actdb_remove(aObjects) {
this.newTxn("readwrite", STORE_NAME, (txn, store) => {
aObjects.forEach((aObject) => {
let object = {
manifest: aObject.manifest,
name: aObject.name,
description: aObject.description
};
debug("Going to remove " + JSON.stringify(object));
store.delete(this.createId(object));
});
}, 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);
this.newTxn("readonly", STORE_NAME, function (txn, store) {
let index = store.index("name");
let request = index.mozGetAll(aObject.options.name);
request.onsuccess = function findSuccess(aEvent) {
debug("Request successful. Record count: " + aEvent.target.result.length);
if (!txn.result) {
txn.result = {
name: aObject.options.name,
options: []
};
}
aEvent.target.result.forEach(function(result) {
if (!aMatch(result))
return;
txn.result.options.push({
manifest: result.manifest,
icon: result.icon,
description: result.description
});
});
}
}.bind(this), aSuccess, aError);
}
}
var Activities = {
messages: [
// 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() {
this.messages.forEach(function(msgName) {
ppmm.addMessageListener(msgName, this);
}, this);
Services.obs.addObserver(this, "xpcom-shutdown", false);
this.db = new ActivitiesDb();
this.db.init();
this.callers = {};
},
observe: function activities_observe(aSubject, aTopic, aData) {
this.messages.forEach(function(msgName) {
ppmm.removeMessageListener(msgName, this);
}, this);
ppmm = null;
if (this.db) {
this.db.close();
this.db = null;
}
Services.obs.removeObserver(this, "xpcom-shutdown");
},
/**
* Starts an activity by doing:
* - finds a list of matching activities.
* - calls the UI glue to get the user choice.
* - fire an system message of type "activity" to this app, sending the
* activity data as a payload.
*/
startActivity: function activities_startActivity(aMsg) {
debug("StartActivity: " + JSON.stringify(aMsg));
let self = this;
let successCb = function successCb(aResults) {
debug(JSON.stringify(aResults));
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?
self.removeCaller(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 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.
// 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) }
});
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
});
});
// Now fire success with the array of choices.
caller.mm.sendAsyncMessage("Activity:FireSuccess",
{
"id": aMsg.id,
"result": results
});
self.removeCaller(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) {
// Something unexpected happened. Should we send an error back?
debug("Error in startActivity: " + aError + "\n");
};
let matchFunc = function matchFunc(aResult) {
// If the activity is in the developer mode activity list, only let the
// system app be a provider.
let isSystemApp = false;
let isDevModeActivity = false;
try {
isSystemApp =
aResult.manifest == Services.prefs.getCharPref("b2g.system_manifest_url");
isDevModeActivity =
Services.prefs.getCharPref("dom.activities.developer_mode_only")
.split(",").indexOf(aMsg.options.name) !== -1;
} catch(e) {}
if (isDevModeActivity && !isSystemApp) {
return false;
}
return ActivitiesServiceFilter.match(aMsg.options.data,
aResult.description.filters);
};
this.db.find(aMsg, successCb, errorCb, matchFunc);
},
trySendAndCleanup: function activities_trySendAndCleanup(aId, aName, aPayload) {
try {
this.callers[aId].mm.sendAsyncMessage(aName, aPayload);
} finally {
this.removeCaller(aId);
}
},
receiveMessage: function activities_receiveMessage(aMessage) {
let mm = aMessage.target;
let msg = aMessage.json;
let caller;
let obsData;
if (aMessage.name == "Activity:PostResult" ||
aMessage.name == "Activity:PostError" ||
aMessage.name == "Activity:Ready") {
caller = this.callers[msg.id];
if (!caller) {
debug("!! caller is null for msg.id=" + msg.id);
return;
}
obsData = JSON.stringify({ manifestURL: caller.manifestURL,
pageURL: caller.pageURL,
success: aMessage.name == "Activity:PostResult" });
}
switch(aMessage.name) {
case "Activity:Start":
Services.obs.notifyObservers(null, "activity-opened", msg.childID);
this.callers[msg.id] = { mm: mm,
manifestURL: msg.manifestURL,
childID: msg.childID,
pageURL: msg.pageURL };
this.startActivity(msg);
break;
case "Activity:Ready":
caller.childMM = mm;
break;
case "Activity:PostResult":
this.trySendAndCleanup(msg.id, "Activity:FireSuccess", msg);
break;
case "Activity:PostError":
this.trySendAndCleanup(msg.id, "Activity:FireError", msg);
break;
case "Activities:Register":
this.db.add(msg,
function onSuccess(aEvent) {
debug("Activities:Register:OK");
Services.obs.notifyObservers(null, "new-activity-registered-success", null);
mm.sendAsyncMessage("Activities:Register:OK", null);
},
function onError(aEvent) {
msg.error = "REGISTER_ERROR";
debug("Activities:Register:KO");
Services.obs.notifyObservers(null, "new-activity-registered-failure", null);
mm.sendAsyncMessage("Activities:Register:KO", msg);
});
break;
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;
}
},
removeCaller: function activities_removeCaller(id) {
Services.obs.notifyObservers(null, "activity-closed",
this.callers[id].childID);
delete this.callers[id];
}
}
Activities.init();

View File

@ -1,129 +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"
this.EXPORTED_SYMBOLS = ['ActivitiesServiceFilter'];
this.ActivitiesServiceFilter = {
match: function(aValues, aFilters) {
function matchValue(aValue, aFilter, aFilterObj) {
if (aFilter !== null) {
// Custom functions for the different types.
switch (typeof(aFilter)) {
case 'boolean':
return aValue === aFilter;
case 'number':
return Number(aValue) === aFilter;
case 'string':
return String(aValue) === aFilter;
default: // not supported
return false;
}
}
// Pattern.
if (('pattern' in aFilterObj)) {
var pattern = String(aFilterObj.pattern);
var patternFlags = '';
if (('patternFlags' in aFilterObj)) {
patternFlags = String(aFilterObj.patternFlags);
}
var re = new RegExp('^(?:' + pattern + ')$', patternFlags);
return re.test(aValue);
}
// Validation of the min/Max.
if (('min' in aFilterObj) || ('max' in aFilterObj)) {
// Min value.
if (('min' in aFilterObj) &&
aFilterObj.min > aValue) {
return false;
}
// Max value.
if (('max' in aFilterObj) &&
aFilterObj.max < aValue) {
return false;
}
}
return true;
}
// this function returns true if the value matches with the filter object
function matchObject(aValue, aFilterObj) {
// Let's consider anything an array.
let filters = ('value' in aFilterObj)
? (Array.isArray(aFilterObj.value)
? aFilterObj.value
: [aFilterObj.value])
: [ null ];
let values = Array.isArray(aValue) ? aValue : [aValue];
for (var filterId = 0; filterId < filters.length; ++filterId) {
for (var valueId = 0; valueId < values.length; ++valueId) {
if (matchValue(values[valueId], filters[filterId], aFilterObj)) {
return true;
}
}
}
return false;
}
// Creation of a filter map useful to know what has been
// matched and what is not.
let filtersMap = {}
for (let filter in aFilters) {
// Convert this filter in an object if needed
let filterObj = aFilters[filter];
if (Array.isArray(filterObj) || typeof(filterObj) !== 'object') {
filterObj = {
required: false,
value: filterObj
}
}
filtersMap[filter] = { filter: filterObj,
found: false };
}
// For any incoming property.
for (let prop in aValues) {
// If this is unknown for the app, let's continue.
if (!(prop in filtersMap)) {
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;
}
filtersMap[prop].found = true;
}
// Required filters:
for (let filter in filtersMap) {
if (filtersMap[filter].filter.required && !filtersMap[filter].found) {
return false;
}
}
return true;
}
}

View File

@ -1,104 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "Activity.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/ContentChild.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsIConsoleService.h"
#include "nsIDocShell.h"
#include "nsIDocument.h"
using namespace mozilla::dom;
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Activity)
NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
NS_IMPL_ADDREF_INHERITED(Activity, DOMRequest)
NS_IMPL_RELEASE_INHERITED(Activity, DOMRequest)
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*> aGivenProto)
{
return MozActivityBinding::Wrap(aCx, this, aGivenProto);
}
nsresult
Activity::Initialize(nsPIDOMWindowInner* aWindow,
JSContext* aCx,
const ActivityOptions& aOptions)
{
MOZ_ASSERT(aWindow);
nsCOMPtr<nsIDocument> document = aWindow->GetExtantDoc();
bool isActive;
aWindow->GetDocShell()->GetIsActive(&isActive);
if (!isActive &&
!nsContentUtils::IsChromeDoc(document)) {
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService("@mozilla.org/dom/dom-request-service;1");
rs->FireErrorAsync(static_cast<DOMRequest*>(this),
NS_LITERAL_STRING("NotUserInput"));
nsCOMPtr<nsIConsoleService> console(
do_GetService("@mozilla.org/consoleservice;1"));
NS_ENSURE_TRUE(console, NS_OK);
nsString message =
NS_LITERAL_STRING("Can only start activity from user input or chrome code");
console->LogStringMessage(message.get());
return NS_OK;
}
// Instantiate a JS proxy that will do the child <-> parent communication
// with the JS implementation of the backend.
nsresult rv;
mProxy = do_CreateInstance("@mozilla.org/dom/activities/proxy;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
// We're about the pass the dictionary to a JS-implemented component, so
// rehydrate it in a system scode so that security wrappers don't get in the
// way. See bug 1161748 comment 16.
bool ok;
JS::Rooted<JS::Value> optionsValue(aCx);
{
JSAutoCompartment ac(aCx, xpc::PrivilegedJunkScope());
ok = ToJSValue(aCx, aOptions, &optionsValue);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
}
ok = JS_WrapValue(aCx, &optionsValue);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
ContentChild *cpc = ContentChild::GetSingleton();
uint64_t childID = cpc ? cpc->GetID() : 0;
mProxy->StartActivity(static_cast<nsIDOMDOMRequest*>(this), optionsValue,
aWindow, childID);
return NS_OK;
}
Activity::~Activity()
{
if (mProxy) {
mProxy->Cleanup();
}
}
Activity::Activity(nsPIDOMWindowInner* aWindow)
: DOMRequest(aWindow)
{
}

View File

@ -1,59 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_activities_Activity_h
#define mozilla_dom_activities_Activity_h
#include "DOMRequest.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/MozActivityBinding.h"
#include "nsIActivityProxy.h"
#include "mozilla/Preferences.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
class Activity : public DOMRequest
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(Activity, DOMRequest)
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<Activity>
Constructor(const GlobalObject& aOwner,
const ActivityOptions& aOptions,
ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aOwner.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
RefPtr<Activity> activity = new Activity(window);
aRv = activity->Initialize(window, aOwner.Context(), aOptions);
return activity.forget();
}
explicit Activity(nsPIDOMWindowInner* aWindow);
protected:
nsresult Initialize(nsPIDOMWindowInner* aWindow,
JSContext* aCx,
const ActivityOptions& aOptions);
nsCOMPtr<nsIActivityProxy> mProxy;
~Activity();
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_activities_Activity_h

View File

@ -1,33 +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("-- 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]);

View File

@ -1,134 +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/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsISyncMessageSender");
function debug(aMsg) {
//dump("-- ActivityProxy " + Date.now() + " : " + aMsg + "\n");
}
/**
* nsIActivityProxy implementation
* We keep a reference to the C++ Activity object, and
* communicate with the Message Manager to know when to
* fire events on it.
*/
function ActivityProxy() {
debug("ActivityProxy");
this.activity = null;
let inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
debug("inParent: " + inParent);
Cu.import(inParent ? "resource://gre/modules/Webapps.jsm"
: "resource://gre/modules/AppsServiceChild.jsm");
}
ActivityProxy.prototype = {
startActivity: function actProxy_startActivity(aActivity, aOptions, aWindow,
aChildID) {
debug("startActivity");
this.window = aWindow;
this.activity = aActivity;
this.id = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator)
.generateUUID().toString();
// Retrieve the app's manifest url from the principal, so that we can
// later notify when the activity handler called postResult or postError
let principal = aWindow.document.nodePrincipal;
let appId = principal.appId;
let manifestURL = (appId != Ci.nsIScriptSecurityManager.NO_APP_ID &&
appId != Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID)
? DOMApplicationRegistry.getManifestURLByLocalId(appId)
: null;
// 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;
}
// Check the activities that are restricted to be used in dev mode.
let devMode = false;
let isDevModeActivity = false;
try {
devMode = Services.prefs.getBoolPref("dom.apps.developer_mode");
isDevModeActivity =
Services.prefs.getCharPref("dom.activities.developer_mode_only")
.split(",").indexOf(aOptions.name) !== -1;
} catch(e) {}
if (isDevModeActivity && !devMode) {
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,
childID: aChildID });
},
receiveMessage: function actProxy_receiveMessage(aMessage) {
debug("Got message: " + aMessage.name);
let msg = aMessage.json;
if (msg.id != this.id)
return;
debug("msg=" + JSON.stringify(msg));
switch(aMessage.name) {
case "Activity:FireSuccess":
debug("FireSuccess");
Services.DOMRequest.fireSuccess(this.activity,
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.
this.cleanup();
},
cleanup: function actProxy_cleanup() {
debug("cleanup");
if (cpmm && !this.cleanedUp) {
cpmm.removeMessageListener("Activity:FireSuccess", this);
cpmm.removeMessageListener("Activity:FireError", this);
}
this.cleanedUp = true;
},
classID: Components.ID("{ba9bd5cb-76a0-4ecf-a7b3-d2f7c43c5949}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIActivityProxy])
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityProxy]);

View File

@ -1,80 +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");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsISyncMessageSender");
function debug(aMsg) {
//dump("-- ActivityRequestHandler.js " + Date.now() + " : " + aMsg + "\n");
}
/**
* nsIDOMMozActivityRequestHandler implementation.
*/
function ActivityRequestHandler() {
debug("ActivityRequestHandler");
// 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 an
// ActivityRequestHandler object.
}
ActivityRequestHandler.prototype = {
init: function arh_init(aWindow) {
this._window = aWindow;
},
__init: function arh___init(aId, aOptions, aReturnValue) {
this._id = aId;
this._options = aOptions;
this._returnValue = aReturnValue;
},
get source() {
// 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) {
if (this._returnValue) {
cpmm.sendAsyncMessage("Activity:PostResult", {
"id": this._id,
"result": aResult
});
Services.obs.notifyObservers(null, "activity-success", this._id);
} else {
Cu.reportError("postResult() can't be called when 'returnValue': 'true' isn't declared in manifest.webapp");
throw new Error("postResult() can't be called when 'returnValue': 'true' isn't declared in manifest.webapp");
}
},
postError: function arh_postError(aError) {
cpmm.sendAsyncMessage("Activity:PostError", {
"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.nsIDOMGlobalPropertyInitializer
])
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityRequestHandler]);

View File

@ -1,94 +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/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 });
// Gecko should ignore |postResult| calls for WebActivities with no returnValue
// We need to pass returnValue to ActivityRequestHandler constructor to then properly
// decide if should call postResult or not
let handler = new aWindow.ActivityRequestHandler(aMessage.id, aMessage.payload, aMessage.target.returnValue);
// 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]);

View File

@ -1,13 +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/.
XPIDL_SOURCES += [
'nsIActivityProxy.idl',
'nsIActivityUIGlue.idl',
]
XPIDL_MODULE = 'dom_activities'

View File

@ -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 "nsISupports.idl"
interface mozIDOMWindow;
/**
* Implemented by @mozilla.org/dom/activities/proxy;1
*/
[scriptable, uuid(87653623-d864-4b03-8874-96808b8cdb81)]
interface nsIActivityProxy : nsISupports
{
void startActivity(in nsISupports /* MozActivity */ activity,
in jsval options,
in mozIDOMWindow window,
in unsigned long long childID);
void cleanup();
};

View File

@ -1,45 +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 "nsISupports.idl"
[scriptable, function, uuid(674b6e69-05f0-41da-aabd-4184ea85c9d8)]
interface nsIActivityUIGlueCallback : nsISupports
{
/**
* 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(3caef69f-3569-4b19-bcea-1cfb0fee4466)]
interface nsIActivityUIGlue : nsISupports
{
/**
* 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 callback The callback to send the index of the choosen activity, or the result.
*/
void chooseActivity(in jsval options, in jsval activities,
in nsIActivityUIGlueCallback callback);
};

View File

@ -1,40 +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/.
DIRS += ['interfaces']
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
MOCHITEST_CHROME_MANIFESTS += ['tests/mochi/mochitest.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',
]
LOCAL_INCLUDES += [
'/dom/base',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View File

@ -1,37 +0,0 @@
var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
const ACTIVITY_GLUE_CID = Components.ID("{f4cfbe10-a106-4cd1-b04e-0d2a6aac138b}");
const SYS_MSG_GLUE_CID = Components.ID("{b0b6b9af-bc4e-4200-bffe-fb7691065ec9}");
const gRootUrl = "http://test/chrome/dom/activities/tests/mochi/";
function registerComponent(aObject, aDescription, aContract, aCid) {
info("Registering " + aCid);
var componentManager =
Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
componentManager.registerFactory(aCid, aDescription, aContract, aObject);
// Keep the id on the object so we can unregister later.
aObject.cid = aCid;
}
function unregisterComponent(aObject) {
info("Unregistering " + aObject.cid);
var componentManager =
Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
componentManager.unregisterFactory(aObject.cid, aObject);
}
function cbError(aEvent) {
ok(false, "Error callback invoked " +
aEvent.target.error.name + " " + aEvent.target.error.message);
finish();
}
function unexpectedSuccess(aMsg) {
return function() {
ok(false, "Should not have succeeded: " + aMsg);
finish();
}
}

View File

@ -1,17 +0,0 @@
{
"name": "Random app",
"activities": {
"import-app": { "blob": { "required": true } },
"bug1176712": [{
"filters": {
"type": "type1"
},
"href": "href1"
}, {
"filters": {
"type": "type2"
},
"href": "href2"
}]
}
}

View File

@ -1 +0,0 @@
Content-Type: application/manifest+json

View File

@ -1,11 +0,0 @@
[DEFAULT]
skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
support-files =
common.js
system.webapp
system.webapp^headers^
manifest.webapp
manifest.webapp^headers^
[test_dev_mode_activity.html]
[test_same_name_multiple_filters.html]

View File

@ -1,6 +0,0 @@
{
"name": "System app",
"activities": {
"import-app": { "blob": { "required": true } }
}
}

View File

@ -1 +0,0 @@
Content-Type: application/manifest+json

View File

@ -1,269 +0,0 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id={1123846}
-->
<head>
<title>Test for Bug {1123846}</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript"
src="http://test/chrome/dom/activities/tests/mochi/common.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={1123846}">Mozilla Bug {1123846}</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
/**
* Tests the developer mode activities that can only be provided by the
* system app.
*
* We test the following:
* 1) No dev mode, no system app installed (failure).
* 2) No dev mode, system app installed (failure).
* 3) No dev mode, system app and other app installed (failure).
* 4) Dev mode, system app and other app installed (success, only system app returned).
*/
var gGenerator = runTest();
function go() {
SpecialPowers.pushPermissions(
[{ "type": "webapps-manage", "allow": 1, "context": document },
{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document }],
function() {
SpecialPowers.pushPrefEnv(
{'set': [["dom.mozBrowserFramesEnabled", true],
["dom.sysmsg.enabled", true],
["dom.apps.developer_mode", false],
["dom.activities.developer_mode_only", "import-app"]]},
continueTest) });
}
SimpleTest.waitForExplicitFinish();
var systemAppUrl = gRootUrl + "system.webapp";
var otherAppUrl = gRootUrl + "manifest.webapp";
function installApp(aUrl) {
var request = navigator.mozApps.install(aUrl, { });
request.onerror = cbError;
request.onsuccess = continueTest;
return request;
}
function installSystemApp() {
return installApp(systemAppUrl);
}
function installOtherApp() {
return installApp(otherAppUrl);
}
function uninstall(aApp) {
info("Uninstalling " + (aApp ? aApp.manifestURL : "NO APP!!"));
var request = navigator.mozApps.mgmt.uninstall(aApp);
request.onerror = cbError;
request.onsuccess = continueTest;
}
var ActivityGlue = {
// nsISupports implementation.
QueryInterface: function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIFactory) ||
iid.equals(Ci.nsIActivityUIGlue)) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
},
// nsIFactory implementation.
createInstance: function(outer, iid) {
return this.QueryInterface(iid);
},
// nsIActivityUIGlue implementation.
chooseActivity: function(aOptions, aActivities, aCallback) {
aCallback.handleEvent(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY,
aActivities.length == 1 ? 0 : -1);
}
};
var SystemMessageGlue = {
// nsISupports implementation.
QueryInterface: function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIFactory) ||
iid.equals(Ci.nsISystemMessageGlue)) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
},
// nsIFactory implementation.
createInstance: function(outer, iid) {
return this.QueryInterface(iid);
},
// nsISystemMessageGlue implementation.
openApp(pageURL, manifestURL, type, target, showApp, onlyShowApp, extra) {
// We should only try to open a page in the system app.
is(manifestURL, systemAppUrl, "Opening a page in the system app.");
}
};
registerComponent(ActivityGlue,
"Activity Glue",
"@mozilla.org/dom/activities/ui-glue;1",
ACTIVITY_GLUE_CID);
registerComponent(SystemMessageGlue,
"System Message Glue",
"@mozilla.org/dom/messages/system-message-glue;1",
SYS_MSG_GLUE_CID);
function finish() {
unregisterComponent(ActivityGlue);
unregisterComponent(SystemMessageGlue);
obsService.removeObserver(continueTest, "new-activity-registered-success");
obsService.removeObserver(continueTest, "new-activity-registered-failure");
SimpleTest.finish();
}
function continueTest() {
try {
gGenerator.next();
} catch (e if e instanceof StopIteration) {
finish();
}
}
var obsService = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
obsService.addObserver(continueTest, "new-activity-registered-success", false);
obsService.addObserver(continueTest, "new-activity-registered-failure", false);
/**
* Test dev mode activity.
*/
function runTest() {
SpecialPowers.autoConfirmAppInstall(continueTest);
yield undefined;
SpecialPowers.autoConfirmAppUninstall(continueTest);
yield undefined;
// Check how many apps we are starting with.
var request = navigator.mozApps.mgmt.getAll();
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
var initialAppsCount = request.result.length;
info("Starting with " + initialAppsCount + " apps installed.");
// 1) No dev mode, no system app installed (failure).
var activity = new MozActivity({ name: "import-app" });
activity.onerror = function() {
ok(true, "1) No dev mode, no system app installed");
continueTest();
}
activity.onsuccess = unexpectedSuccess("1) No dev mode, no system app installed");
yield undefined;
// 2) No dev mode, system app installed (failure).
// Configure the system app manifest url.
SpecialPowers.pushPrefEnv(
{'set': [["b2g.system_manifest_url", systemAppUrl]]},
continueTest);
yield undefined;
// Install the system app.
request = installSystemApp();
yield undefined;
var systemApp = request.result;
ok(systemApp, "systemApp is non-null");
// yielding for the activity install observer.
yield undefined;
activity = new MozActivity({ name: "import-app" });
activity.onerror = function() {
ok(true, "2) No dev mode, system app installed");
continueTest();
}
activity.onsuccess = unexpectedSuccess("2) No dev mode, system app installed");
yield undefined;
// 3) No dev mode, system app and other app installed (failure).
request = installOtherApp();
yield undefined;
var otherApp = request.result;
ok(otherApp, "otherApp is non-null");
// yielding for the activity install observer.
yield undefined;
activity = new MozActivity({ name: "import-app" });
activity.onerror = function() {
ok(true, "3) No dev mode, system app and other app installed");
continueTest();
}
activity.onsuccess = unexpectedSuccess("3) No dev mode, system app and other app installed");
yield undefined;
// 4) Dev mode, system app and other app installed.
SpecialPowers.pushPrefEnv(
{'set': [["dom.apps.developer_mode", true]]},
continueTest);
yield undefined;
activity = new MozActivity({ name: "import-app" });
activity.onsuccess = function() {
ok(true, "4) Dev mode, system app and other app installed");
continueTest();
}
activity.onerror = function(aEvent) {
ok(false, "4) Got error: " + aEvent.error.name);
finish();
}
yield undefined;
// Cleanup
uninstall(systemApp);
yield undefined;
uninstall(otherApp);
yield undefined;
// Check that we restored the app registry.
request = navigator.mozApps.mgmt.getAll();
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
}
addLoadEvent(go);
</script>
</pre>
</body>
</html>

View File

@ -1,220 +0,0 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id={1176712}
-->
<head>
<title>Test for Bug {1176712}</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript"
src="http://test/chrome/dom/activities/tests/mochi/common.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={1176712}">Mozilla Bug {1176712}</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
var gGenerator = runTest();
function go() {
SpecialPowers.pushPermissions(
[{ "type": "webapps-manage", "allow": 1, "context": document },
{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document }],
function() {
SpecialPowers.pushPrefEnv(
{'set': [["dom.mozBrowserFramesEnabled", true],
["dom.sysmsg.enabled", true]]},
continueTest) });
}
SimpleTest.waitForExplicitFinish();
function installApp(aUrl) {
var request = navigator.mozApps.install(aUrl, { });
request.onerror = cbError;
request.onsuccess = continueTest;
return request;
}
function uninstall(aApp) {
info("Uninstalling " + (aApp ? aApp.manifestURL : "NO APP!!"));
var request = navigator.mozApps.mgmt.uninstall(aApp);
request.onerror = cbError;
request.onsuccess = continueTest;
}
var ActivityGlue = {
// nsISupports implementation.
QueryInterface: function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIFactory) ||
iid.equals(Ci.nsIActivityUIGlue)) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
},
// nsIFactory implementation.
createInstance: function(outer, iid) {
return this.QueryInterface(iid);
},
// nsIActivityUIGlue implementation.
chooseActivity: function(aOptions, aActivities, aCallback) {
aCallback.handleEvent(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY,
aActivities.length == 1 ? 0 : -1);
}
};
var SystemMessageGlue = {
// nsISupports implementation.
QueryInterface: function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIFactory) ||
iid.equals(Ci.nsISystemMessageGlue)) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
},
// nsIFactory implementation.
createInstance: function(outer, iid) {
return this.QueryInterface(iid);
},
// nsISystemMessageGlue implementation.
openApp(pageURL, manifestURL, type, target, showApp, onlyShowApp, extra) {
}
};
registerComponent(ActivityGlue,
"Activity Glue",
"@mozilla.org/dom/activities/ui-glue;1",
ACTIVITY_GLUE_CID);
registerComponent(SystemMessageGlue,
"System Message Glue",
"@mozilla.org/dom/messages/system-message-glue;1",
SYS_MSG_GLUE_CID);
function finish() {
unregisterComponent(ActivityGlue);
unregisterComponent(SystemMessageGlue);
SimpleTest.finish();
}
function continueTest() {
try {
gGenerator.next();
} catch (e if e instanceof StopIteration) {
finish();
}
}
function runTest() {
SpecialPowers.autoConfirmAppInstall(continueTest);
yield undefined;
SpecialPowers.autoConfirmAppUninstall(continueTest);
yield undefined;
// Check how many apps we are starting with.
var request = navigator.mozApps.mgmt.getAll();
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
var initialAppsCount = request.result.length;
info("Starting with " + initialAppsCount + " apps installed.");
// Before app installed
var activity = new MozActivity({
name: "bug1176712",
data: {
type: "type1"
}
});
activity.onsuccess = unexpectedSuccess("Shouldn't launch unregistered activity");
activity.onerror = () => {
ok(activity.error.name == "NO_PROVIDER", "Expected NO_PROVIDER");
continueTest();
};
yield undefined;
var activity = new MozActivity({
name: "bug1176712",
data: {
type: "type2"
}
});
activity.onsuccess = unexpectedSuccess("Shouldn't launch unregistered activity");
activity.onerror = () => {
ok(activity.error.name == "NO_PROVIDER", "Expected NO_PROVIDER");
continueTest();
};
yield undefined;
var request = installApp(gRootUrl + "manifest.webapp");
yield undefined;
var app = request.result;
ok(app, "App installed");
// After app installed
var activity = new MozActivity({
name: "bug1176712",
data: {
type: "type1"
}
});
activity.onsuccess = function() {
ok(true, "Activity launch succeed");
continueTest();
}
activity.onerror = cbError;
yield undefined;
var activity = new MozActivity({
name: "bug1176712",
data: {
type: "type2"
}
});
activity.onsuccess = function() {
ok(true, "Activity launch succeed");
continueTest();
}
activity.onerror = cbError;
yield undefined;
// Cleanup
uninstall(app);
yield undefined;
// Check that we restored the app registry.
request = navigator.mozApps.mgmt.getAll();
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
}
addLoadEvent(go);
</script>
</pre>
</body>
</html>

View File

@ -1,157 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
Components.utils.import("resource:///modules/ActivitiesServiceFilter.jsm")
do_check_true(!!ActivitiesServiceFilter);
// No requests, no filters:
do_check_true(ActivitiesServiceFilter.match(null, null));
do_check_true(ActivitiesServiceFilter.match({}, {}));
// No filters:
do_check_true(ActivitiesServiceFilter.match({foobar: 42}, null));
// Empty request:
do_check_true(ActivitiesServiceFilter.match({}, {a: 'foobar', b: [1, 2, 3], c: 42}));
// Simple match:
do_check_true(ActivitiesServiceFilter.match({a: 'foobar'},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({a: 'foobar', b: 2, c: true},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({a: 'foobar', b: 2, c: 42},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({a: 'foobar2'},
{a: 'foobar', b: [1, 2, 3], c: 42}));
// Simple match in array:
do_check_true(ActivitiesServiceFilter.match({b: 2},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({b: 4},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({b: [2, 4]},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({b: [4, 5]},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_false(ActivitiesServiceFilter.match({a: [4, 'foobar2']},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({a: [4, 'foobar']},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({a: ['foo', 'bar']},
{a: 'foo'}));
// Unknown property
do_check_true(ActivitiesServiceFilter.match({k: 4},
{a: 'foobar', b: [1, 2, 3], c: 42}));
do_check_true(ActivitiesServiceFilter.match({k: [1,2,3,4]},
{a: 'foobar', b: [1, 2, 3], c: 42}));
// Required/non required
do_check_false(ActivitiesServiceFilter.match({},
{a: { required: true, value: 'foobar'}}));
do_check_true(ActivitiesServiceFilter.match({a: 'foobar'},
{a: { required: true, value: 'foobar'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'foobar2'},
{a: { required: true, value: 'foobar'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'foobar2'},
{a: { required: true, value: ['a', 'b', 'foobar']}}));
do_check_true(ActivitiesServiceFilter.match({a: 'foobar'},
{a: { required: true, value: ['a', 'b', 'foobar']}}));
do_check_true(ActivitiesServiceFilter.match({a: ['k', 'z', 'foobar']},
{a: { required: true, value: ['a', 'b', 'foobar']}}));
do_check_false(ActivitiesServiceFilter.match({a: ['k', 'z', 'foobar2']},
{a: { required: true, value: ['a', 'b', 'foobar']}}));
// Empty values
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: { required: true}}));
do_check_false(ActivitiesServiceFilter.match({},
{a: { required: true}}));
// Boolean
do_check_true(ActivitiesServiceFilter.match({a: false},
{a: { required: true, value: false}}));
do_check_false(ActivitiesServiceFilter.match({a: true},
{a: { required: true, value: false}}));
do_check_true(ActivitiesServiceFilter.match({a: [false, true]},
{a: { required: true, value: false}}));
do_check_true(ActivitiesServiceFilter.match({a: [false, true]},
{a: { required: true, value: [false,true]}}));
// Number
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: { required: true, value: 42}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, value: 42}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 1}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 2}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 3}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, max: 1}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, max: 2}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, max: 3}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 1, max: 1}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 1, max: 2}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 2, max: 2}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, value: 'foo'}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 100, max: 0}}));
do_check_true(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 'a', max: 'b'}}));
do_check_false(ActivitiesServiceFilter.match({a: 2},
{a: { required: true, min: 10, max: 1}}));
// String
do_check_true(ActivitiesServiceFilter.match({a: 'foo'},
{a: { required: true, value: 'foo'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'foo2'},
{a: { required: true, value: 'foo'}}));
// Number VS string
do_check_true(ActivitiesServiceFilter.match({a: '42'},
{a: { required: true, value: 42}}));
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: { required: true, value: '42'}}));
do_check_true(ActivitiesServiceFilter.match({a: '-42e+12'},
{a: { required: true, value: -42e+12}}));
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: { required: true, min: '1', max: '50'}}));
do_check_true(ActivitiesServiceFilter.match({a: '42'},
{a: 42 }));
do_check_true(ActivitiesServiceFilter.match({a: 42},
{a: '42' }));
do_check_false(ActivitiesServiceFilter.match({a: 42},
{a: { min: '44' }}));
do_check_false(ActivitiesServiceFilter.match({a: 42},
{a: { max: '0' }}));
// String + Pattern
do_check_true(ActivitiesServiceFilter.match({a: 'foobar'},
{a: { required: true, pattern: 'foobar'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'aafoobar'},
{a: { required: true, pattern: 'foobar'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'aaFOOsdsad'},
{a: { required: true, pattern: 'foo', patternFlags: 'i'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'aafoobarasdsad'},
{a: { required: true, pattern: 'foo'}}));
do_check_false(ActivitiesServiceFilter.match({a: 'aaFOOsdsad'},
{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'}}));
}

View File

@ -1,6 +0,0 @@
[DEFAULT]
head =
tail =
skip-if = toolkit == 'gonk'
[test_activityFilters.js]

View File

@ -36,7 +36,6 @@ this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import('resource://gre/modules/ActivitiesService.jsm');
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/AppDownloadManager.jsm");
Cu.import("resource://gre/modules/osfile.jsm");

View File

@ -77,10 +77,6 @@
DOMInterfaces = {
'MozActivity': {
'nativeType': 'mozilla::dom::Activity',
},
'AbstractWorker': {
'concrete': False
},

View File

@ -41,7 +41,6 @@ DIRS += [
'apps',
'base',
'bluetooth',
'activities',
'archivereader',
'bindings',
'battery',

View File

@ -1,17 +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/. */
[Pref="dom.sysmsg.enabled",
JSImplementation="@mozilla.org/dom/activities/request-handler;1",
ChromeConstructor(DOMString id, optional ActivityOptions options, optional boolean returnvalue),
ChromeOnly]
interface ActivityRequestHandler
{
[UnsafeInPrerendering]
void postResult(any result);
[UnsafeInPrerendering]
void postError(DOMString error);
[Pure, Cached, Frozen]
readonly attribute ActivityOptions source;
};

View File

@ -1,16 +0,0 @@
/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
dictionary ActivityOptions {
DOMString name = "";
any data = null;
boolean getFilterResults = false;
};
[Pref="dom.sysmsg.enabled",
Constructor(optional ActivityOptions options)]
interface MozActivity : DOMRequest {
};

View File

@ -19,7 +19,6 @@ PREPROCESSED_WEBIDL_FILES = [
WEBIDL_FILES = [
'AbstractWorker.webidl',
'ActivityRequestHandler.webidl',
'AddonManager.webidl',
'AnalyserNode.webidl',
'Animatable.webidl',
@ -321,7 +320,6 @@ WEBIDL_FILES = [
'MobileMessageThread.webidl',
'MouseEvent.webidl',
'MouseScrollEvent.webidl',
'MozActivity.webidl',
'MozCellBroadcast.webidl',
'MozCellBroadcastMessage.webidl',
'MozIcc.webidl',

View File

@ -5708,14 +5708,6 @@ if test -n "$MOZ_PAY"; then
fi
AC_SUBST(MOZ_PAY)
dnl ========================================================
dnl = Enable Browser Support for Activities
dnl ========================================================
if test -n "$MOZ_ACTIVITIES"; then
AC_DEFINE(MOZ_ACTIVITIES)
fi
AC_SUBST(MOZ_ACTIVITIES)
dnl ========================================================
dnl = Enable Support for AudioChannelManager API
dnl ========================================================