Merge m-c to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-04-30 15:26:15 +02:00
commit f45fcac3a1
38 changed files with 776 additions and 261 deletions

View File

@ -48,7 +48,8 @@ ActivitiesDialog.prototype = {
return;
SystemAppProxy.removeEventListener("mozContentEvent", act_getChoice);
activity.callback.handleEvent(evt.detail.value !== undefined
activity.callback.handleEvent(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY,
evt.detail.value !== undefined
? evt.detail.value
: -1);
});
@ -56,16 +57,22 @@ ActivitiesDialog.prototype = {
SystemAppProxy.dispatchEvent(detail);
},
chooseActivity: function ap_chooseActivity(aName, aActivities, aCallback) {
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(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY, -1);
return;
}
this.activities.push({
name: aName,
name: aOptions.name,
list: aActivities,
callback: aCallback
});
Services.tm.currentThread.dispatch(this, Ci.nsIEventTarget.DISPATCH_NORMAL);
},
classID: Components.ID("{70a83123-7467-4389-a309-3e81c74ad002}"),
classID: Components.ID("{3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIActivityUIGlue, Ci.nsIRunnable])
}

View File

@ -21,8 +21,8 @@ contract @mozilla.org/browser/directory-provider;1 {9181eb7c-6f87-11e1-90b1-4f59
category xpcom-directory-providers browser-directory-provider @mozilla.org/browser/directory-provider;1
# ActivitiesGlue.js
component {70a83123-7467-4389-a309-3e81c74ad002} ActivitiesGlue.js
contract @mozilla.org/dom/activities/ui-glue;1 {70a83123-7467-4389-a309-3e81c74ad002}
component {3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e} ActivitiesGlue.js
contract @mozilla.org/dom/activities/ui-glue;1 {3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e}
# ProcessGlobal.js
component {1a94c87a-5ece-4d11-91e1-d29c29f21b28} ProcessGlobal.js

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="0292e64ef8451df104dcf9ac3b2c6749b81684dd"/>
@ -102,7 +102,7 @@
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="bdce08ae0f7c92e5f1d2bafd777213702d6445f0"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="d7755abaf703f86228e3938a3e204121b254638d"/>
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="431afac2ebfdd9c1c8402b413ff5914ed448e961"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="4f46930827957afbce500a4a920755a218bf3155"/>
</manifest>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="65fba428f8d76336b33ddd9e15900357953600ba">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>

View File

@ -19,7 +19,11 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<<<<<<< local
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
=======
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
>>>>>>> other
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="0292e64ef8451df104dcf9ac3b2c6749b81684dd"/>
@ -102,7 +106,7 @@
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="bdce08ae0f7c92e5f1d2bafd777213702d6445f0"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="d7755abaf703f86228e3938a3e204121b254638d"/>
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="431afac2ebfdd9c1c8402b413ff5914ed448e961"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="4f46930827957afbce500a4a920755a218bf3155"/>
</manifest>

View File

@ -18,7 +18,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "2ba34e93a4be9aa6c52fcd9303bd7d78cffb58b7",
"revision": "ecde92711ca63dd62dd6008686532c0cc52c75dd",
"repo_path": "/integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="badc73ee7f108fa631150bded0cc57e92aad810e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a3437e7e204e32f0f93880a43bfc0cef909cb84d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -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);
};

View File

@ -206,65 +206,79 @@ let Activities = {
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(aResultType, aResult) {
switch(aResultType) {
case Ci.nsIActivityUIGlueCallback.NATIVE_ACTIVITY: {
Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
"id": aMsg.id,
"result": aResult
});
break;
}
case Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY: {
debug("Activity choice: " + aResult);
function getActivityChoice(aChoice) {
debug("Activity choice: " + aChoice);
// 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) {
Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
"id": aMsg.id,
"error": "NO_PROVIDER"
});
delete Activities.callers[aMsg.id];
return;
}
// The user has cancelled the choice, fire an error.
if (aChoice === -1) {
Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
"id": aMsg.id,
"error": "ActivityCanceled"
});
delete Activities.callers[aMsg.id];
return;
}
// The user has cancelled the choice, fire an error.
if (aResult === -1) {
Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
"id": aMsg.id,
"error": "ActivityCanceled"
});
delete Activities.callers[aMsg.id];
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 Activities.callers[aMsg.id];
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 Activities.callers[aMsg.id];
return;
}
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),
{
"manifestURL": Activities.callers[aMsg.id].manifestURL,
"pageURL": Activities.callers[aMsg.id].pageURL
});
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": Activities.callers[aMsg.id].manifestURL,
"pageURL": Activities.callers[aMsg.id].pageURL
});
if (!result.description.returnValue) {
Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
"id": aMsg.id,
"result": null
});
// 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];
if (!result.description.returnValue) {
Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
"id": aMsg.id,
"result": null
});
// 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];
}
break;
}
}
};
let glue = Cc["@mozilla.org/dom/activities/ui-glue;1"]
.createInstance(Ci.nsIActivityUIGlue);
glue.chooseActivity(aResults.name, aResults.options, getActivityChoice);
glue.chooseActivity(aMsg.options, aResults.options, getActivityChoice);
};
let errorCb = function errorCb(aError) {

View File

@ -0,0 +1,55 @@
/* -*- Mode: C++; 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/. */
#include "DOMMMIError.h"
#include "mozilla/dom/DOMMMIErrorBinding.h"
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_CLASS(DOMMMIError)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMMMIError, DOMError)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMMMIError, DOMError)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMMMIError)
NS_INTERFACE_MAP_END_INHERITING(DOMError)
NS_IMPL_ADDREF_INHERITED(DOMMMIError, DOMError)
NS_IMPL_RELEASE_INHERITED(DOMMMIError, DOMError)
DOMMMIError::DOMMMIError(nsPIDOMWindow* aWindow, const nsAString& aName,
const nsAString& aMessage, const nsAString& aServiceCode,
const Nullable<int16_t>& aInfo)
: DOMError(aWindow, aName, aMessage)
, mServiceCode(aServiceCode)
, mInfo(aInfo)
{
}
JSObject*
DOMMMIError::WrapObject(JSContext* aCx)
{
return DOMMMIErrorBinding::Wrap(aCx, this);
}
// WebIDL interface
/* static */ already_AddRefed<DOMMMIError>
DOMMMIError::Constructor(const GlobalObject& aGlobal,
const nsAString& aServiceCode,
const nsAString& aName,
const nsAString& aMessage,
const Nullable<int16_t>& aInfo,
ErrorResult& aRv) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
nsRefPtr<DOMMMIError> error = new DOMMMIError(window, aName, aMessage,
aServiceCode, aInfo);
return error.forget();
}

View File

@ -0,0 +1,54 @@
/* -*- Mode: C++; 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/. */
#ifndef mozilla_dom_MmiError_h
#define mozilla_dom_MmiError_h
#include "mozilla/dom/DOMError.h"
namespace mozilla {
namespace dom {
class DOMMMIError MOZ_FINAL : public DOMError
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMMMIError, DOMError)
DOMMMIError(nsPIDOMWindow* aWindow, const nsAString& aName,
const nsAString& aMessage, const nsAString& aServiceCode,
const Nullable<int16_t>& aInfo);
virtual JSObject*
WrapObject(JSContext* aCx) MOZ_OVERRIDE;
// WebIDL interface
static already_AddRefed<DOMMMIError>
Constructor(const GlobalObject& aGlobal, const nsAString& aServiceCode,
const nsAString& aName, const nsAString& aMessage,
const Nullable<int16_t>& aInfo, ErrorResult& aRv);
void
GetServiceCode(nsString& aServiceCode) const
{
aServiceCode = mServiceCode;
}
Nullable<int16_t>
GetAdditionalInformation() const
{
return mInfo;
}
private:
nsString mServiceCode;
Nullable<int16_t> mInfo;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MmiError_h

View File

@ -5,11 +5,13 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
'DOMMMIError.h',
'MobileConnection.h',
'MobileConnectionArray.h',
]
SOURCES += [
'DOMMMIError.cpp',
'MobileConnection.cpp',
'MobileConnectionArray.cpp',
]

View File

@ -387,6 +387,23 @@ function selectNetworkAutomaticallyAndWait() {
return Promise.all(promises);
}
/**
* Send a MMI message.
*
* Fulfill params: An object contains MMI result.
* Reject params: A DOMMMIError.
*
* @param aMmi
* A MMI string.
*
* @return A deferred promise.
*/
function sendMMI(aMmi) {
let request = mobileConnection.sendMMI(aMmi);
return wrapDomRequestAsPromise(request)
.then(() => request.result, () => { throw request.error });
}
/**
* Set data connection enabling state and wait for "datachange" event.
*

View File

@ -14,6 +14,7 @@ qemu = true
[test_mobile_data_location.js]
[test_mobile_data_state.js]
[test_mobile_mmi.js]
[test_mobile_mmi_change_pin.js]
[test_mobile_roaming_preference.js]
[test_call_barring_get_option.js]
[test_call_barring_set_error.js]

View File

@ -1,107 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 20000;
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head.js";
SpecialPowers.addPermission("mobileconnection", true, document);
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let mobileConnection;
ifr.onload = function() {
mobileConnection = ifr.contentWindow.navigator.mozMobileConnections[0];
tasks.run();
};
document.body.appendChild(ifr);
let tasks = {
// List of test functions. Each of them should call |tasks.next()| when
// completed or |tasks.abort()| to jump to the last one.
_tasks: [],
_nextTaskIndex: 0,
push: function(func) {
this._tasks.push(func);
},
next: function() {
let index = this._nextTaskIndex++;
let task = this._tasks[index];
try {
task();
} catch (ex) {
ok(false, "test task[" + index + "] throws: " + ex);
// Run last task as clean up if possible.
if (index != this._tasks.length - 1) {
this.abort();
}
}
},
abort: function() {
this._tasks[this._tasks.length - 1]();
},
run: function() {
this.next();
}
};
tasks.push(function verifyInitialState() {
log("Verifying initial state.");
ok(mobileConnection instanceof ifr.contentWindow.MozMobileConnection,
"mobileConnection is instanceof " + mobileConnection.constructor);
tasks.next();
});
tasks.push(function testGettingIMEI() {
function testGettingIMEI() {
log("Test *#06# ...");
let request = mobileConnection.sendMMI("*#06#");
ok(request instanceof DOMRequest,
"request is instanceof " + request.constructor);
let MMI_CODE = "*#06#";
return sendMMI(MMI_CODE)
.then(function resolve(aResult) {
ok(true, MMI_CODE + " success");
is(aResult.serviceCode, "scImei", "Service code IMEI");
// IMEI is hardcoded as "000000000000000".
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c
// (The result of +CGSN).
is(aResult.statusMessage, "000000000000000", "Emulator IMEI");
is(aResult.additionalInformation, undefined, "No additional information");
}, function reject() {
ok(false, MMI_CODE + " should not fail");
});
}
request.onsuccess = function onsuccess(event) {
ok(true, "request success");
is(typeof event.target.result, "object", "typeof result object");
ok(event.target.result instanceof Object, "result instanceof Object");
is(event.target.result.statusMessage, "000000000000000", "Emulator IMEI");
is(event.target.result.serviceCode, "scImei", "Service code IMEI");
is(event.target.result.additionalInformation, undefined,
"No additional information");
tasks.next();
}
request.onerror = function onerror() {
ok(false, "request should not error");
tasks.abort();
};
});
tasks.push(function testInvalidMMICode(){
function testInvalidMMICode() {
log("Test invalid MMI code ...");
let request = mobileConnection.sendMMI("InvalidMMICode");
ok(request instanceof DOMRequest,
"request is instanceof " + request.constructor);
let MMI_CODE = "InvalidMMICode";
return sendMMI(MMI_CODE)
.then(function resolve() {
ok(false, MMI_CODE + " should not success");
}, function reject(aError) {
ok(true, MMI_CODE + " fail");
is(aError.name, "emMmiError", "MMI error name");
is(aError.message, "", "No message");
is(aError.serviceCode, "", "No serviceCode");
is(aError.additionalInformation, null, "No additional information");
});
}
request.onsuccess = function onsuccess(event) {
ok(false, "request should not success");
tasks.abort();
};
request.onerror = function onerror() {
ok(true, "request error");
is(request.error.name, "emMmiError", "MMI error name");
tasks.next();
};
});
// WARNING: All tasks should be pushed before this!!!
tasks.push(function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document);
finish();
// Start test
startTestCommon(function() {
return Promise.resolve()
.then(() => testGettingIMEI())
.then(() => testInvalidMMICode());
});

View File

@ -0,0 +1,111 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head.js";
// PIN is hardcoded as "0000" by default.
// See it here {B2G_HOME}/external/qemu/telephony/sim_card.c,
// in asimcard_create().
const TEST_DATA = [
// Test passing no pin.
{
pin: "",
newPin: "0000",
newPinAgain: "1111",
expectedError: {
name: "emMmiError",
additionalInformation: null
}
},
// Test passing no newPin.
{
pin: "0000",
newPin: "",
newPinAgain: "",
expectedError: {
name: "emMmiError",
additionalInformation: null
}
},
// Test passing mismatched newPin.
{
pin: "0000",
newPin: "0000",
newPinAgain: "1111",
expectedError: {
name: "emMmiErrorMismatchPin",
additionalInformation: null
}
},
// Test passing invalid pin (< 4 digit).
{
pin: "000",
newPin: "0000",
newPinAgain: "0000",
expectedError: {
name: "emMmiErrorInvalidPin",
additionalInformation: null
}
},
// Test passing invalid newPin (> 8 digit).
{
pin: "0000",
newPin: "000000000",
newPinAgain: "000000000",
expectedError: {
name: "emMmiErrorInvalidPin",
additionalInformation: null
}
},
// Test passing incorrect pin.
{
pin: "1234",
newPin: "0000",
newPinAgain: "0000",
expectedError: {
name: "emMmiErrorBadPin",
// The default pin retries is 3, failed once becomes to 2
additionalInformation: 2
}
},
// Test changing pin successfully (Reset the retries).
{
pin: "0000",
newPin: "0000",
newPinAgain: "0000"
}
];
function testChangePin(aPin, aNewPin, aNewPinAgain, aExpectedError) {
let MMI_CODE = "**04*" + aPin + "*" + aNewPin + "*" + aNewPinAgain + "#";
log("Test " + MMI_CODE);
return sendMMI(MMI_CODE)
.then(function resolve(aResult) {
ok(!aExpectedError, MMI_CODE + " success");
is(aResult.serviceCode, "scPin", "Check service code");
is(aResult.statusMessage, "smPinChanged", "Check status message");
is(aResult.additionalInformation, undefined, "Check additional information");
}, function reject(aError) {
ok(aExpectedError, MMI_CODE + " fail");
is(aError.name, aExpectedError.name, "Check name");
is(aError.message, "", "Check message");
is(aError.serviceCode, "scPin", "Check service code");
is(aError.additionalInformation, aExpectedError.additionalInformation,
"Chech additional information");
});
}
// Start test
startTestCommon(function() {
let promise = Promise.resolve();
for (let i = 0; i < TEST_DATA.length; i++) {
let data = TEST_DATA[i];
promise = promise.then(() => testChangePin(data.pin,
data.newPin,
data.newPinAgain,
data.expectedError));
}
return promise;
});

View File

@ -57,8 +57,6 @@ const CELLBROADCASTMESSAGE_CID =
Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
const CELLBROADCASTETWSINFO_CID =
Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}");
const DOMMMIERROR_CID =
Components.ID("{6b204c42-7928-4e71-89ad-f90cd82aff96}");
const ICCCARDLOCKERROR_CID =
Components.ID("{08a71987-408c-44ff-93fd-177c0a85c3dd}");
@ -422,20 +420,6 @@ DOMCLIRStatus.prototype = {
m: 'r'}
};
function DOMMMIError() {
}
DOMMMIError.prototype = {
classDescription: "DOMMMIError",
classID: DOMMMIERROR_CID,
contractID: "@mozilla.org/dom/mmi-error;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
__init: function(serviceCode, name, message, additionalInformation) {
this.__DOM_IMPL__.init(name, message);
this.serviceCode = serviceCode;
this.additionalInformation = additionalInformation;
},
};
function IccCardLockError() {
}
IccCardLockError.prototype = {
@ -2128,7 +2112,7 @@ RILContentHelper.prototype = {
}
let result = {
serviceCode: message.mmiServiceCode,
serviceCode: message.mmiServiceCode || "",
additionalInformation: message.additionalInformation
};
@ -2139,7 +2123,7 @@ RILContentHelper.prototype = {
} else {
let mmiError = new requestWindow.DOMMMIError(result.serviceCode,
message.errorMsg,
null,
"",
result.additionalInformation);
Services.DOMRequest.fireDetailedError(request, mmiError);
}
@ -2239,5 +2223,4 @@ RILContentHelper.prototype = {
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper,
DOMMMIError,
IccCardLockError]);

View File

@ -19,9 +19,7 @@ category profile-after-change RadioInterfaceLayer @mozilla.org/ril;1
# RILContentHelper.js
component {472816e1-1fd6-4405-996c-806f9ea68174} RILContentHelper.js
component {6b204c42-7928-4e71-89ad-f90cd82aff96} RILContentHelper.js
component {08a71987-408c-44ff-93fd-177c0a85c3dd} RILContentHelper.js
contract @mozilla.org/ril/content-helper;1 {472816e1-1fd6-4405-996c-806f9ea68174}
contract @mozilla.org/dom/mmi-error;1 {6b204c42-7928-4e71-89ad-f90cd82aff96}
contract @mozilla.org/dom/icccardlock-error;1 {08a71987-408c-44ff-93fd-177c0a85c3dd}
category profile-after-change RILContentHelper @mozilla.org/ril/content-helper;1

View File

@ -304,7 +304,7 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"DOMImplementation",
// IMPORTANT: Do not change this list without review from a DOM peer!
"DOMMMIError",
{name: "DOMMMIError", b2g: true, pref: "dom.mobileconnection.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"DOMParser",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -4,13 +4,15 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[JSImplementation="@mozilla.org/dom/mmi-error;1",
[Pref="dom.mobileconnection.enabled",
Constructor(DOMString serviceCode,
DOMString name,
optional DOMString message = "",
optional DOMString additionalInformation = "")]
optional short? additionalInformation = null)]
interface DOMMMIError : DOMError {
[Constant]
readonly attribute DOMString serviceCode;
readonly attribute any additionalInformation;
[Constant]
readonly attribute short? additionalInformation;
};

View File

@ -84,7 +84,6 @@ WEBIDL_FILES = [
'DOMError.webidl',
'DOMException.webidl',
'DOMImplementation.webidl',
'DOMMMIError.webidl',
'DOMParser.webidl',
'DOMPoint.webidl',
'DOMQuad.webidl',
@ -544,6 +543,7 @@ if CONFIG['MOZ_B2G_BT']:
if CONFIG['MOZ_B2G_RIL']:
WEBIDL_FILES += [
'DOMMMIError.webidl',
'IccCardLockError.webidl',
'MozCellBroadcast.webidl',
'MozCellBroadcastEvent.webidl',

View File

@ -637,49 +637,7 @@ public abstract class GeckoApp
} else {
// something went wrong.
Log.e(LOGTAG, "Received Contact:Add message with no email nor phone number");
}
} else if (event.equals("Intent:GetHandlers")) {
Intent intent = GeckoAppShell.getOpenURIIntent((Context) this, message.optString("url"),
message.optString("mime"), message.optString("action"), message.optString("title"));
String[] handlers = GeckoAppShell.getHandlersForIntent(intent);
List<String> appList = Arrays.asList(handlers);
JSONObject handlersJSON = new JSONObject();
handlersJSON.put("apps", new JSONArray(appList));
EventDispatcher.sendResponse(message, handlersJSON);
} else if (event.equals("Intent:Open")) {
GeckoAppShell.openUriExternal(message.optString("url"),
message.optString("mime"), message.optString("packageName"),
message.optString("className"), message.optString("action"), message.optString("title"));
} else if (event.equals("Intent:OpenForResult")) {
Intent intent = GeckoAppShell.getOpenURIIntent(this,
message.optString("url"),
message.optString("mime"),
message.optString("action"),
message.optString("title"));
intent.setClassName(message.optString("packageName"), message.optString("className"));
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
final JSONObject originalMessage = message;
ActivityHandlerHelper.startIntentForActivity(this,
intent,
new ActivityResultHandler() {
@Override
public void onActivityResult (int resultCode, Intent data) {
JSONObject response = new JSONObject();
try {
if (data != null) {
response.put("extras", bundleToJSON(data.getExtras()));
}
response.put("resultCode", resultCode);
} catch (JSONException e) {
Log.w(LOGTAG, "Error building JSON response.", e);
}
EventDispatcher.sendResponse(originalMessage, response);
}
});
}
} else if (event.equals("Locale:Set")) {
setLocale(message.getString("locale"));
} else if (event.equals("NativeApp:IsDebuggable")) {
@ -840,23 +798,6 @@ public abstract class GeckoApp
});
}
private JSONObject bundleToJSON(Bundle bundle) {
JSONObject json = new JSONObject();
if (bundle == null) {
return json;
}
for (String key : bundle.keySet()) {
try {
json.put(key, bundle.get(key));
} catch (JSONException e) {
Log.w(LOGTAG, "Error building JSON response.", e);
}
}
return json;
}
private void addFullScreenPluginView(View view) {
if (mFullScreenPluginView != null) {
Log.w(LOGTAG, "Already have a fullscreen plugin view");
@ -1355,6 +1296,7 @@ public abstract class GeckoApp
GeckoAppShell.setNotificationClient(makeNotificationClient());
NotificationHelper.init(getApplicationContext());
IntentHelper.init(this);
}
/**
@ -1568,9 +1510,6 @@ public abstract class GeckoApp
registerEventListener("Update:Install");
registerEventListener("PrivateBrowsing:Data");
registerEventListener("Contact:Add");
registerEventListener("Intent:Open");
registerEventListener("Intent:OpenForResult");
registerEventListener("Intent:GetHandlers");
registerEventListener("Locale:Set");
registerEventListener("NativeApp:IsDebuggable");
registerEventListener("SystemUI:Visibility");
@ -2104,8 +2043,6 @@ public abstract class GeckoApp
unregisterEventListener("Update:Install");
unregisterEventListener("PrivateBrowsing:Data");
unregisterEventListener("Contact:Add");
unregisterEventListener("Intent:Open");
unregisterEventListener("Intent:GetHandlers");
unregisterEventListener("Locale:Set");
unregisterEventListener("NativeApp:IsDebuggable");
unregisterEventListener("SystemUI:Visibility");
@ -2127,6 +2064,7 @@ public abstract class GeckoApp
if (mTextSelection != null)
mTextSelection.destroy();
NotificationHelper.destroy();
IntentHelper.destroy();
if (SmsManager.getInstance() != null) {
SmsManager.getInstance().stop();

View File

@ -0,0 +1,144 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.JSONUtils;
import org.mozilla.gecko.util.WebActivityMapper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import java.util.Arrays;
import java.util.List;
public final class IntentHelper implements GeckoEventListener {
private static final String LOGTAG = "GeckoIntentHelper";
private static final String[] EVENTS = {
"Intent:GetHandlers",
"Intent:Open",
"Intent:OpenForResult",
"WebActivity:Open"
};
private static IntentHelper instance;
private Activity activity;
private IntentHelper(Activity activity) {
this.activity = activity;
for (String event : EVENTS) {
GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
}
}
public static IntentHelper init(Activity activity) {
if (instance == null) {
instance = new IntentHelper(activity);
} else {
Log.w(LOGTAG, "IntentHelper.init() called twice, ignoring.");
}
return instance;
}
public static void destroy() {
if (instance != null) {
for (String event : EVENTS) {
GeckoAppShell.getEventDispatcher().unregisterEventListener(event, instance);
}
instance = null;
}
}
@Override
public void handleMessage(String event, JSONObject message) {
try {
if (event.equals("Intent:GetHandlers")) {
getHandlers(message);
} else if (event.equals("Intent:Open")) {
open(message);
} else if (event.equals("Intent:OpenForResult")) {
openForResult(message);
} else if (event.equals("WebActivity:Open")) {
openWebActivity(message);
}
} catch (JSONException e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
}
}
private void getHandlers(JSONObject message) throws JSONException {
final Intent intent = GeckoAppShell.getOpenURIIntent(activity,
message.optString("url"),
message.optString("mime"),
message.optString("action"),
message.optString("title"));
final List<String> appList = Arrays.asList(GeckoAppShell.getHandlersForIntent(intent));
final JSONObject response = new JSONObject();
response.put("apps", new JSONArray(appList));
EventDispatcher.sendResponse(message, response);
}
private void open(JSONObject message) throws JSONException {
GeckoAppShell.openUriExternal(message.optString("url"),
message.optString("mime"),
message.optString("packageName"),
message.optString("className"),
message.optString("action"),
message.optString("title"));
}
private void openForResult(final JSONObject message) throws JSONException {
Intent intent = GeckoAppShell.getOpenURIIntent(activity,
message.optString("url"),
message.optString("mime"),
message.optString("action"),
message.optString("title"));
intent.setClassName(message.optString("packageName"), message.optString("className"));
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
ActivityHandlerHelper.startIntentForActivity(activity, intent, new ResultHandler(message));
}
private void openWebActivity(JSONObject message) throws JSONException {
final Intent intent = WebActivityMapper.getIntentForWebActivity(message.getJSONObject("activity"));
ActivityHandlerHelper.startIntentForActivity(activity, intent, new ResultHandler(message));
}
private static class ResultHandler implements ActivityResultHandler {
private final JSONObject message;
public ResultHandler(JSONObject message) {
this.message = message;
}
@Override
public void onActivityResult(int resultCode, Intent data) {
JSONObject response = new JSONObject();
try {
if (data != null) {
response.put("extras", JSONUtils.bundleToJSON(data.getExtras()));
response.put("uri", data.getData().toString());
}
response.put("resultCode", resultCode);
} catch (JSONException e) {
Log.w(LOGTAG, "Error building JSON response.", e);
}
EventDispatcher.sendResponse(message, response);
}
}
}

View File

@ -70,6 +70,7 @@ gujar.sources += [
'util/StringUtils.java',
'util/ThreadUtils.java',
'util/UiAsyncTask.java',
'util/WebActivityMapper.java',
]
gujar.extra_jars = [
'gecko-mozglue.jar'
@ -287,6 +288,7 @@ gbjar.sources += [
'home/TopSitesThumbnailView.java',
'home/TwoLinePageRow.java',
'InputMethods.java',
'IntentHelper.java',
'JavaAddonManager.java',
'LightweightTheme.java',
'LightweightThemeDrawable.java',

View File

@ -9,7 +9,16 @@ import java.util.UUID;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Bundle;
import android.util.Log;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID;
public final class JSONUtils {
private static final String LOGTAG = "GeckoJSONUtils";
private JSONUtils() {}
public static UUID getUUID(String name, JSONObject json) {
@ -25,4 +34,21 @@ public final class JSONUtils {
throw new IllegalArgumentException(name + "=" + uuidString, e);
}
}
public static JSONObject bundleToJSON(Bundle bundle) {
if (bundle == null || bundle.isEmpty()) {
return null;
}
JSONObject json = new JSONObject();
for (String key : bundle.keySet()) {
try {
json.put(key, bundle.get(key));
} catch (JSONException e) {
Log.w(LOGTAG, "Error building JSON response.", e);
}
}
return json;
}
}

View File

@ -0,0 +1,151 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.util;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
import java.util.HashMap;
import java.util.Map;
public final class WebActivityMapper {
private static final Map<String, WebActivityMapping> activityMap = new HashMap<String, WebActivityMapping>();
static {
activityMap.put("dial", new DialMapping());
activityMap.put("open", new OpenMapping());
activityMap.put("pick", new PickMapping());
activityMap.put("send", new SendMapping());
activityMap.put("view", new ViewMapping());
};
private static abstract class WebActivityMapping {
// Cannot return null
public abstract String getAction();
public String getMime(JSONObject data) throws JSONException {
return null;
}
public String getUri(JSONObject data) throws JSONException {
return null;
}
public void putExtras(JSONObject data, Intent intent) throws JSONException {}
}
/**
* Provides useful defaults for mime type and uri.
*/
private static abstract class BaseMapping extends WebActivityMapping {
/**
* If 'type' is present in data object, uses the value as the MIME type.
*/
public String getMime(JSONObject data) throws JSONException {
return data.optString("type", null);
}
/**
* If 'uri' or 'url' is present in data object, uses the respecitve value as the Uri.
*/
public String getUri(JSONObject data) throws JSONException {
// Will return uri or url if present.
String uri = data.optString("uri", null);
return uri != null ? uri : data.optString("url", null);
}
}
public static Intent getIntentForWebActivity(JSONObject message) throws JSONException {
final String name = message.getString("name").toLowerCase();
final JSONObject data = message.getJSONObject("data");
final WebActivityMapping mapping = activityMap.get(name);
final Intent intent = new Intent(mapping.getAction());
final String mime = mapping.getMime(data);
if (!TextUtils.isEmpty(mime)) {
intent.setType(mime);
}
final String uri = mapping.getUri(data);
if (!TextUtils.isEmpty(uri)) {
intent.setData(Uri.parse(uri));
}
mapping.putExtras(data, intent);
return intent;
}
private static class DialMapping extends WebActivityMapping {
@Override
public String getAction() {
return Intent.ACTION_DIAL;
}
@Override
public String getUri(JSONObject data) throws JSONException {
return "tel:" + data.getString("number");
}
}
private static class OpenMapping extends BaseMapping {
@Override
public String getAction() {
return Intent.ACTION_VIEW;
}
}
private static class PickMapping extends BaseMapping {
@Override
public String getAction() {
return Intent.ACTION_GET_CONTENT;
}
}
private static class SendMapping extends BaseMapping {
@Override
public String getAction() {
return Intent.ACTION_SEND;
}
@Override
public void putExtras(JSONObject data, Intent intent) throws JSONException {
optPutExtra("text", Intent.EXTRA_TEXT, data, intent);
optPutExtra("html_text", Intent.EXTRA_HTML_TEXT, data, intent);
optPutExtra("stream", Intent.EXTRA_STREAM, data, intent);
}
}
private static class ViewMapping extends BaseMapping {
@Override
public String getAction() {
return Intent.ACTION_VIEW;
}
@Override
public String getMime(JSONObject data) {
// MozActivity adds a type 'url' here, we don't want to set the MIME to 'url'.
String type = data.optString("type", null);
if ("url".equals(type) || "uri".equals(type)) {
return null;
} else {
return type;
}
}
}
private static void optPutExtra(String key, String extraName, JSONObject data, Intent intent) {
final String extraValue = data.optString(key);
if (!TextUtils.isEmpty(extraValue)) {
intent.putExtra(extraName, extraValue);
}
}
}

View File

@ -41,6 +41,9 @@ let WebappRT = {
pref("dom.mozTCPSocket.enabled", true),
// Don't check for updates in webapp processes to avoid duplicate notifications.
pref("browser.webapps.checkForUpdates", 0),
// Enabled system messages for web activity support
pref("dom.sysmsg.enabled", true),
],
init: function(aStatus, aUrl, aCallback) {

View File

@ -0,0 +1,31 @@
/* 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/Messaging.jsm");
function ActivitiesGlue() { }
ActivitiesGlue.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIActivityUIGlue]),
classID: Components.ID("{e4deb5f6-d5e3-4fce-bc53-901dd9951c48}"),
// Ignore aActivities results on Android, go straight to Android intents.
chooseActivity: function ap_chooseActivity(aOptions, aActivities, aCallback) {
sendMessageToJava({
type: "WebActivity:Open",
activity: { name: aOptions.name, data: aOptions.data }
}, (result) => {
aCallback.handleEvent(Ci.nsIActivityUIGlueCallback.NATIVE_ACTIVITY, result);
});
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivitiesGlue]);

View File

@ -120,3 +120,7 @@ category update-timer WebappsUpdateTimer @mozilla.org/webapps-update-timer;1,get
# ColorPicker.js
component {430b987f-bb9f-46a3-99a5-241749220b29} ColorPicker.js
contract @mozilla.org/colorpicker;1 {430b987f-bb9f-46a3-99a5-241749220b29}
# ActivitiesGlue.js
component {e4deb5f6-d5e3-4fce-bc53-901dd9951c48} ActivitiesGlue.js
contract @mozilla.org/dom/activities/ui-glue;1 {e4deb5f6-d5e3-4fce-bc53-901dd9951c48}

View File

@ -11,6 +11,7 @@ XPIDL_SOURCES += [
XPIDL_MODULE = 'MobileComponents'
EXTRA_COMPONENTS += [
'ActivitiesGlue.js',
'AddonUpdateService.js',
'BlocklistPrompt.js',
'ColorPicker.js',

View File

@ -133,6 +133,7 @@
@BINPATH@/components/directory.xpt
@BINPATH@/components/docshell.xpt
@BINPATH@/components/dom.xpt
@BINPATH@/components/dom_activities.xpt
@BINPATH@/components/dom_apps.xpt
@BINPATH@/components/dom_base.xpt
@BINPATH@/components/dom_canvas.xpt
@ -399,6 +400,13 @@
@BINPATH@/components/SystemMessageManager.js
@BINPATH@/components/SystemMessageManager.manifest
@BINPATH@/components/Activities.manifest
@BINPATH@/components/ActivitiesGlue.js
@BINPATH@/components/ActivityProxy.js
@BINPATH@/components/ActivityRequestHandler.js
@BINPATH@/components/ActivityWrapper.js
@BINPATH@/components/ActivityMessageConfigurator.js
@BINPATH@/components/TCPSocket.js
@BINPATH@/components/TCPSocketParentIntermediary.js
@BINPATH@/components/TCPServerSocket.js