Merge m-c to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-09-26 13:33:30 +02:00
commit 59d863b149
118 changed files with 5276 additions and 1100 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

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="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -132,7 +132,7 @@
<!-- Flame specific things -->
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
<project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/>
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="960533f716ce31dfad357e87fa2f1d9ee5e94674"/>
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="52c909e821d107d414f851e267dedcd7aae2cebf"/>
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="893238eb1215f8fd4f3747169170cc5e1cc33969"/>
<project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/>
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="30b96dfca99cb384bf520a16b81f3aba56f09907"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "253fcdd727387f6ad023de9aed30a20e7b8bd72d",
"revision": "95521d1e0cf64f0d95be0cf643931e20119a7387",
"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="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>

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="a06714c555ca7068545f10b4437a16c14cd8e7f5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4e9aa22d15b77e5b3d7e763128ead2caffd3b801"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -159,7 +159,6 @@
@BINPATH@/components/dom_system_gonk.xpt
#endif
#ifdef MOZ_B2G_RIL
@BINPATH@/components/dom_voicemail.xpt
@BINPATH@/components/dom_icc.xpt
@BINPATH@/components/dom_cellbroadcast.xpt
@BINPATH@/components/dom_wappush.xpt
@ -200,6 +199,7 @@
@BINPATH@/components/dom_threads.xpt
@BINPATH@/components/dom_traversal.xpt
@BINPATH@/components/dom_views.xpt
@BINPATH@/components/dom_voicemail.xpt
#ifdef MOZ_WEBSPEECH
@BINPATH@/components/dom_webspeechrecognition.xpt
#endif
@ -448,6 +448,8 @@
@BINPATH@/components/RILContentHelper.js
@BINPATH@/components/TelephonyService.js
@BINPATH@/components/TelephonyService.manifest
@BINPATH@/components/VoicemailService.js
@BINPATH@/components/VoicemailService.manifest
#endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL
#ifndef MOZ_WIDGET_GONK

View File

@ -1605,7 +1605,7 @@ pref("loop.soft_start_hostname", "soft-start.loop.services.mozilla.com");
pref("loop.server", "https://loop.services.mozilla.com");
pref("loop.seenToS", "unseen");
pref("loop.legal.ToS_url", "https://accounts.firefox.com/legal/terms");
pref("loop.legal.ToS_url", "https://call.mozilla.com/legal/terms/");
pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/");
pref("loop.do_not_disturb", false);
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/Firefox-Long.ogg");
@ -1613,6 +1613,7 @@ pref("loop.retry_delay.start", 60000);
pref("loop.retry_delay.limit", 300000);
pref("loop.feedback.baseUrl", "https://input.mozilla.org/api/v1/feedback");
pref("loop.feedback.product", "Loop");
pref("loop.debug.loglevel", "Error");
pref("loop.debug.websocket", false);
pref("loop.debug.sdk", false);

View File

@ -11,7 +11,6 @@ let gCustomize = {
"classic",
"enhanced",
"panel",
"what",
],
_nodes: {},
@ -33,9 +32,6 @@ let gCustomize = {
gAllPages.enabled = true;
gAllPages.enhanced = true;
});
this._nodes.what.addEventListener("click", e => {
gIntro.showPanel();
});
this.updateSelected();
},

View File

@ -11,6 +11,7 @@ let gIntro = {
_nodeIDSuffixes: [
"panel",
"what",
],
_nodes: {},
@ -21,6 +22,7 @@ let gIntro = {
}
this._nodes.panel.addEventListener("popupshowing", e => this._setUpPanel());
this._nodes.what.addEventListener("click", e => this.showPanel());
},
showIfNecessary: function() {
@ -31,11 +33,8 @@ let gIntro = {
},
showPanel: function() {
// Open the customize menu first
gCustomize.showPanel().then(nodes => {
// Point the panel at the 'what' menu item
this._nodes.panel.openPopup(nodes.what);
});
// Point the panel at the 'what' link
this._nodes.panel.openPopup(this._nodes.what);
},
_setUpPanel: function() {

View File

@ -49,21 +49,41 @@ input[type=button] {
right: auto;
}
#newtab-intro-what {
cursor: pointer;
position: absolute;
right: 55px;
top: 15px;
}
#newtab-intro-what:-moz-locale-dir(rtl) {
left: 55px;
right: auto;
}
#newtab-intro-panel {
color: #737373;
color: #6a7b86;
font-size: 15px;
line-height: 20px;
margin-top: -32px;
padding: 10px;
width: 500px;
line-height: 19px;
width: 520px;
}
#newtab-intro-panel h1 {
color: #343f48;
font-family: Open Sans, sans-serif;
font-size: 30px;
margin: 20px;
}
#newtab-intro-panel p {
margin: 10px 20px;
}
#newtab-intro-panel p:last-child {
margin-bottom: 30px;
}
#newtab-intro-what:hover,
#newtab-intro-panel a {
color: #4a90e2;
}
@ -231,12 +251,12 @@ input[type=button] {
#newtab-intro-panel input,
.sponsored-explain input {
background-size: 20px;
height: 20px;
background-size: 18px;
height: 18px;
opacity: 1;
pointer-events: none;
position: static;
width: 20px;
width: 18px;
}
/* CONTROLS */

View File

@ -21,7 +21,7 @@
title="&newtab.pageTitle;">
<xul:panel id="newtab-intro-panel" orient="vertical" type="arrow"
noautohide="true" position="leftcenter topright">
noautohide="true">
<h1>&newtab.intro.header;</h1>
</xul:panel>
@ -43,9 +43,6 @@
<xul:hbox id="newtab-customize-blank" class="newtab-customize-panel-item">
<xul:label>&newtab.customize.blank;</xul:label>
</xul:hbox>
<xul:hbox id="newtab-customize-what" class="newtab-customize-panel-item">
<xul:label>&newtab.customize.what;</xul:label>
</xul:hbox>
</xul:panel>
<div id="newtab-scrollbox">
@ -93,6 +90,8 @@
</div>
<div id="newtab-intro-what">&newtab.customize.what;</div>
<input id="newtab-customize-button" type="button" title="&newtab.customize.title;"/>
</div>

View File

@ -102,6 +102,11 @@ skip-if = os == "linux" # Bug 924307
skip-if = e10s # Bug ?????? - no about:home support yet
[browser_aboutSyncProgress.js]
[browser_action_keyword.js]
skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux
[browser_action_searchengine.js]
skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux
[browser_action_searchengine_alias.js]
skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux
[browser_addKeywordSearch.js]
skip-if = e10s
[browser_alltabslistener.js]
@ -193,7 +198,6 @@ skip-if = e10s # Bug 691614 - no e10s zoom support yet
[browser_bug555767.js]
skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
[browser_bug556061.js]
skip-if = e10s # Bug 932651 - getClipboardData in specialpowersAPI.js not e10s friendly
[browser_bug559991.js]
skip-if = e10s # Bug 691614 - no e10s zoom support yet
[browser_bug561623.js]
@ -440,7 +444,7 @@ skip-if = e10s
[browser_urlbarAutoFillTrimURLs.js]
skip-if = e10s
[browser_urlbarCopying.js]
skip-if = e10s # Bug 932651 - getClipboardData in specialpowersAPI.js not e10s friendly
skip-if = e10s # Bug 1069757 - browser_urlbarCopying.js needs e10s love.
[browser_urlbarEnter.js]
skip-if = e10s # Bug ?????? - obscure non-windows child process crashes on try
[browser_urlbarRevert.js]

View File

@ -8,9 +8,6 @@ function* promise_first_result(inputText) {
gURLBar.value = inputText.slice(0, -1);
EventUtils.synthesizeKey(inputText.slice(-1) , {});
yield promiseSearchComplete();
// On Linux, the popup may or may not be open at this stage. So we need
// additional checks to ensure we wait long enough.
yield promisePopupShown(gURLBar.popup);
let firstResult = gURLBar.popup.richlistbox.firstChild;
return firstResult;

View File

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
let gOriginalEngine;
function* promise_first_result(inputText) {
gURLBar.focus();
gURLBar.value = inputText.slice(0, -1);
EventUtils.synthesizeKey(inputText.slice(-1) , {});
yield promiseSearchComplete();
// On Linux, the popup may or may not be open at this stage. So we need
// additional checks to ensure we wait long enough.
yield promisePopupShown(gURLBar.popup);
let firstResult = gURLBar.popup.richlistbox.firstChild;
return firstResult;
}
add_task(function* () {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
return;
Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET",
"http://example.com/?q={searchTerms}");
let engine = Services.search.getEngineByName("MozSearch");
gOriginalEngine = Services.search.currentEngine;
Services.search.currentEngine = engine;
let tab = gBrowser.selectedTab = gBrowser.addTab();
registerCleanupFunction(() => {
Services.search.currentEngine = gOriginalEngine;
let engine = Services.search.getEngineByName("MozSearch");
Services.search.removeEngine(engine);
try {
gBrowser.removeTab(tab);
} catch(ex) { /* tab may have already been closed in case of failure */ }
return promiseClearHistory();
});
let result = yield promise_first_result("open a search");
isnot(result, null, "Should have a result");
let tabPromise = promiseTabLoaded(gBrowser.selectedTab);
EventUtils.synthesizeMouseAtCenter(result, {});
yield tabPromise;
is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search");
});

View File

@ -0,0 +1,42 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
**/
let gOriginalEngine;
add_task(function* () {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
return;
Services.search.addEngineWithDetails("MozSearch", "", "moz", "", "GET",
"http://example.com/?q={searchTerms}");
let engine = Services.search.getEngineByName("MozSearch");
gOriginalEngine = Services.search.currentEngine;
Services.search.currentEngine = engine;
let tab = gBrowser.selectedTab = gBrowser.addTab();
registerCleanupFunction(() => {
Services.search.currentEngine = gOriginalEngine;
let engine = Services.search.getEngineByName("MozSearch");
Services.search.removeEngine(engine);
try {
gBrowser.removeTab(tab);
} catch(ex) { /* tab may have already been closed in case of failure */ }
return promiseClearHistory();
});
gURLBar.focus();
gURLBar.value = "moz open a searc";
EventUtils.synthesizeKey("h" , {});
yield promiseSearchComplete();
EventUtils.synthesizeKey("VK_RETURN" , { });
yield promiseTabLoaded(gBrowser.selectedTab);
is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search");
});

View File

@ -6,13 +6,11 @@ function* check_a11y_label(inputText, expectedLabel) {
gURLBar.value = inputText.slice(0, -1);
EventUtils.synthesizeKey(inputText.slice(-1) , {});
yield promiseSearchComplete();
// On Linux, the popup may or may not be open at this stage. So we need
// additional checks to ensure we wait long enough.
yield promisePopupShown(gURLBar.popup);
let firstResult = gURLBar.popup.richlistbox.firstChild;
is(firstResult.getAttribute("type"), "action switchtab", "Expect right type attribute");
is(firstResult.label, expectedLabel, "Result a11y label should be as expected");
ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results");
let result = gURLBar.popup.richlistbox.children[1];
is(result.getAttribute("type"), "action switchtab", "Expect right type attribute");
is(result.label, expectedLabel, "Result a11y label should be as expected");
}
add_task(function*() {

View File

@ -3,6 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
add_task(function* test_switchtab_override() {
// This test is only relevant if UnifiedComplete is enabled.
if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
return;
let testURL = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
info("Opening first tab");
@ -37,7 +41,8 @@ add_task(function* test_switchtab_override() {
EventUtils.synthesizeKey("e" , {});
yield deferred.promise;
info("Select first autocomplete popup entry");
info("Select second autocomplete popup entry");
EventUtils.synthesizeKey("VK_DOWN" , {});
EventUtils.synthesizeKey("VK_DOWN" , {});
ok(/moz-action:switchtab/.test(gURLBar.value), "switch to tab entry found");

View File

@ -38,7 +38,8 @@ add_task(function* test_switchtab_override_keynav() {
EventUtils.synthesizeKey("e" , {});
yield searchDeferred.promise;
info("Select first autocomplete popup entry");
info("Select second autocomplete popup entry");
EventUtils.synthesizeKey("VK_DOWN" , {});
EventUtils.synthesizeKey("VK_DOWN" , {});
ok(/moz-action:switchtab/.test(gURLBar.value), "switch to tab entry found");

View File

@ -740,23 +740,28 @@ function promisePopupHidden(popup) {
return promisePopupEvent(popup, "hidden");
}
// NOTE: If you're using this, and attempting to interact with one of the
// autocomplete results, your test is likely to be unreliable on Linux.
// See bug 1073339.
let gURLBarOnSearchComplete = null;
function promiseSearchComplete() {
info("Waiting for onSearchComplete");
let deferred = Promise.defer();
if (!gURLBarOnSearchComplete) {
gURLBarOnSearchComplete = gURLBar.onSearchComplete;
registerCleanupFunction(() => {
gURLBar.onSearchComplete = gURLBarOnSearchComplete;
});
}
return new Promise(resolve => {
if (!gURLBarOnSearchComplete) {
gURLBarOnSearchComplete = gURLBar.onSearchComplete;
registerCleanupFunction(() => {
gURLBar.onSearchComplete = gURLBarOnSearchComplete;
});
}
gURLBar.onSearchComplete = function () {
ok(gURLBar.popupOpen, "The autocomplete popup is correctly open");
gURLBarOnSearchComplete.apply(gURLBar);
deferred.resolve();
}
return deferred.promise;
gURLBar.onSearchComplete = function () {
ok(gURLBar.popupOpen, "The autocomplete popup is correctly open");
gURLBarOnSearchComplete.apply(gURLBar);
resolve();
}
}).then(() => {
// On Linux, the popup may or may not be open at this stage. So we need
// additional checks to ensure we wait long enough.
return promisePopupShown(gURLBar.popup);
});
}

View File

@ -155,7 +155,8 @@
returnValue = action.params.url;
break;
}
case "keyword": {
case "keyword": // Fall through.
case "searchengine": {
returnValue = action.params.input;
break;
}
@ -320,6 +321,12 @@
return;
} else if (action.type == "keyword") {
url = action.params.url;
} else if (action.type == "searchengine") {
let engine = Services.search.getEngineByName(action.params.engineName);
let submission = engine.getSubmission(action.params.searchQuery);
url = submission.uri.spec;
postData = submission.postData;
}
}
continueOperation.call(this);
@ -1003,6 +1010,7 @@
// Check for middle-click or modified clicks on the URL bar
if (gURLBar && this.mInput == gURLBar) {
var url = controller.getValueAt(this.selectedIndex);
var options = {};
// close the autocomplete popup and revert the entered address
this.closePopup();
@ -1019,6 +1027,13 @@
url = action.params.url;
break;
}
case "searchengine": {
let engine = Services.search.getEngineByName(action.params.engineName);
let submission = engine.getSubmission(action.params.searchQuery);
url = submission.uri.spec;
options.postData = submission.postData;
break;
}
default: {
return;
}
@ -1026,7 +1041,7 @@
}
// respect the usual clicking subtleties
openUILink(url, aEvent);
openUILink(url, aEvent, options);
}
]]>
</body>

View File

@ -20,6 +20,9 @@ const LOOP_SESSION_TYPE = {
FXA: 2,
};
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
const PREF_LOG_LEVEL = "loop.debug.loglevel";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
@ -30,9 +33,6 @@ Cu.importGlobalProperties(["URL"]);
this.EXPORTED_SYMBOLS = ["MozLoopService", "LOOP_SESSION_TYPE"];
XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/devtools/Console.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI",
"resource:///modules/loop/MozLoopAPI.jsm");
@ -67,6 +67,15 @@ XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
"@mozilla.org/network/dns-service;1",
"nsIDNSService");
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
XPCOMUtils.defineLazyGetter(this, "log", () => {
let ConsoleAPI = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).ConsoleAPI;
let consoleOptions = {
maxLogLevel: Services.prefs.getCharPref(PREF_LOG_LEVEL).toLowerCase(),
prefix: "Loop",
};
return new ConsoleAPI(consoleOptions);
});
// The current deferred for the registration process. This is set if in progress
// or the registration was successful. This is null if a registration attempt was
@ -112,7 +121,7 @@ CallProgressSocket.prototype = {
connect: function(onSuccess, onError) {
this._onSuccess = onSuccess;
this._onError = onError ||
(reason => {console.warn("MozLoopService::callProgessSocket - ", reason);});
(reason => {log.warn("MozLoopService::callProgessSocket - ", reason);});
if (!onSuccess) {
this._onError("missing onSuccess argument");
@ -193,7 +202,7 @@ CallProgressSocket.prototype = {
msg = JSON.parse(aMsg);
}
catch (error) {
console.error("MozLoopService: error parsing progress message - ", error);
log.error("MozLoopService: error parsing progress message - ", error);
return;
}
@ -211,7 +220,7 @@ CallProgressSocket.prototype = {
*/
_send: function(aMsg) {
if (!this._handshakeComplete) {
console.warn("MozLoopService::_send error - handshake not complete");
log.warn("MozLoopService::_send error - handshake not complete");
return;
}
@ -316,6 +325,7 @@ let MozLoopServiceInternal = {
},
notifyStatusChanged: function(aReason = null) {
log.debug("notifyStatusChanged with reason:", aReason);
Services.obs.notifyObservers(null, "loop-status-changed", aReason);
},
@ -412,7 +422,7 @@ let MozLoopServiceInternal = {
*/
_hawkRequestError: function(error) {
console.error("Loop hawkRequest error:", error);
log.error("Loop hawkRequest error:", error);
throw error;
},
@ -447,9 +457,10 @@ let MozLoopServiceInternal = {
// XXX should do more validation here
if (sessionToken.length === 64) {
Services.prefs.setCharPref(this.getSessionTokenPrefName(sessionType), sessionToken);
log.debug("Stored a hawk session token for sessionType", sessionType);
} else {
// XXX Bubble the precise details up to the UI somehow (bug 1013248).
console.warn("Loop server sent an invalid session token");
log.warn("Loop server sent an invalid session token");
gRegisteredDeferred.reject("session-token-wrong-size");
gRegisteredDeferred = null;
return false;
@ -470,6 +481,7 @@ let MozLoopServiceInternal = {
*/
clearSessionToken: function(sessionType) {
Services.prefs.clearUserPref(this.getSessionTokenPrefName(sessionType));
log.debug("Cleared hawk session token for sessionType", sessionType);
},
/**
@ -494,7 +506,7 @@ let MozLoopServiceInternal = {
// No need to clear the promise here, everything was good, so we don't need
// to re-register.
}, (error) => {
console.error("Failed to register with Loop server: ", error);
log.error("Failed to register with Loop server: ", error);
gRegisteredDeferred.reject(error.errno);
gRegisteredDeferred = null;
});
@ -517,6 +529,7 @@ let MozLoopServiceInternal = {
if (!this.storeSessionToken(sessionType, response.headers))
return;
log.debug("Successfully registered with server for sessionType", sessionType);
this.clearError("registration");
}, (error) => {
// There's other errors than invalid auth token, but we should only do the reset
@ -536,7 +549,7 @@ let MozLoopServiceInternal = {
}
// XXX Bubble the precise details up to the UI somehow (bug 1013248).
console.error("Failed to register with the loop server. Error: ", error);
log.error("Failed to register with the loop server. Error: ", error);
this.setError("registration", error);
throw error;
}
@ -558,6 +571,7 @@ let MozLoopServiceInternal = {
let unregisterURL = "/registration?simplePushURL=" + encodeURIComponent(pushURL);
return this.hawkRequest(sessionType, unregisterURL, "DELETE")
.then(() => {
log.debug("Successfully unregistered from server for sessionType", sessionType);
MozLoopServiceInternal.clearSessionToken(sessionType);
},
error => {
@ -568,7 +582,7 @@ let MozLoopServiceInternal = {
return;
}
console.error("Failed to unregister with the loop server. Error: ", error);
log.error("Failed to unregister with the loop server. Error: ", error);
throw error;
});
},
@ -645,10 +659,10 @@ let MozLoopServiceInternal = {
}
});
} else {
console.warn("Error: missing calls[] in response");
log.warn("Error: missing calls[] in response");
}
} catch (err) {
console.warn("Error parsing calls info", err);
log.warn("Error parsing calls info", err);
}
},
@ -760,7 +774,7 @@ let MozLoopServiceInternal = {
let worker = new ChromeWorker("MozLoopWorker.js");
worker.onmessage = function(e) {
console.log(e.data.ok ?
log.info(e.data.ok ?
"Successfully staged loop report for telemetry upload." :
("Failed to stage loop report. Error: " + e.data.fail));
}
@ -898,7 +912,7 @@ let MozLoopServiceInternal = {
client.launchWebFlow();
},
error => {
console.error(error);
log.error(error);
deferred.reject(error);
}
);
@ -1068,7 +1082,7 @@ this.MozLoopService = {
if (now_serving > ticket) {
// Hot diggity! It's our turn! Activate the service.
console.log("MozLoopService: Activating Loop via soft-start");
log.info("MozLoopService: Activating Loop via soft-start");
Services.prefs.setBoolPref("loop.throttled", false);
buttonNode.hidden = false;
this.initialize();
@ -1234,7 +1248,7 @@ this.MozLoopService = {
try {
Services.prefs.setCharPref("loop." + prefName, value);
} catch (ex) {
console.log("setLoopCharPref had trouble setting " + prefName +
log.error("setLoopCharPref had trouble setting " + prefName +
"; exception: " + ex);
}
},
@ -1256,7 +1270,7 @@ this.MozLoopService = {
try {
return Services.prefs.getCharPref("loop." + prefName);
} catch (ex) {
console.log("getLoopCharPref had trouble getting " + prefName +
log.error("getLoopCharPref had trouble getting " + prefName +
"; exception: " + ex);
return null;
}
@ -1279,7 +1293,7 @@ this.MozLoopService = {
try {
return Services.prefs.getBoolPref("loop." + prefName);
} catch (ex) {
console.log("getLoopBoolPref had trouble getting " + prefName +
log.error("getLoopBoolPref had trouble getting " + prefName +
"; exception: " + ex);
return null;
}
@ -1293,6 +1307,7 @@ this.MozLoopService = {
* @return {Promise} that resolves when the FxA login flow is complete.
*/
logInToFxA: function() {
log.debug("logInToFxA with gFxAOAuthTokenData:", !!gFxAOAuthTokenData);
if (gFxAOAuthTokenData) {
return Promise.resolve(gFxAOAuthTokenData);
}
@ -1320,7 +1335,7 @@ this.MozLoopService = {
gFxAOAuthProfile = result;
MozLoopServiceInternal.notifyStatusChanged("login");
}, error => {
console.error("Failed to retrieve profile", error);
log.error("Failed to retrieve profile", error);
gFxAOAuthProfile = null;
MozLoopServiceInternal.notifyStatusChanged();
});
@ -1340,6 +1355,7 @@ this.MozLoopService = {
* @return {Promise} that resolves when the FxA logout flow is complete.
*/
logOutFromFxA: Task.async(function*() {
log.debug("logOutFromFxA");
yield MozLoopServiceInternal.unregisterFromLoopServer(LOOP_SESSION_TYPE.FXA,
gPushHandler.pushUrl);

View File

@ -211,6 +211,7 @@
@BINPATH@/components/dom_stylesheets.xpt
@BINPATH@/components/dom_telephony.xpt
@BINPATH@/components/dom_traversal.xpt
@BINPATH@/components/dom_voicemail.xpt
#ifdef MOZ_WEBSPEECH
@BINPATH@/components/dom_webspeechrecognition.xpt
#endif

View File

@ -76,7 +76,7 @@ OrganizerQueryAllBookmarks=All Bookmarks
OrganizerQueryTags=Tags
# LOCALIZATION NOTE (tagResultLabel, bookmarkResultLabel, switchtabResultLabel,
# keywordResultLabel)
# keywordResultLabel, searchengineResultLabel)
# Noun used to describe the location bar autocomplete result type
# to users with screen readers
# See createResultLabel() in urlbarBindings.xml
@ -84,6 +84,8 @@ tagResultLabel=Tag
bookmarkResultLabel=Bookmark
switchtabResultLabel=Tab
keywordResultLabel=Keyword
searchengineResultLabel=Search
# LOCALIZATION NOTE (lockPrompt.text)
# %S will be replaced with the application name.

View File

@ -1505,6 +1505,14 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
padding: 0 3px;
}
richlistitem[type~="action"][actiontype="searchengine"] > .ac-title-box > .ac-site-icon {
list-style-image: url("chrome://global/skin/icons/autocomplete-search.svg#search-icon");
}
richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-title-box > .ac-site-icon {
list-style-image: url("chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted");
}
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
color: GrayText;
}

View File

@ -2218,6 +2218,14 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
-moz-image-region: rect(11px, 16px, 22px, 0);
}
richlistitem[type~="action"][actiontype="searchengine"] > .ac-title-box > .ac-site-icon {
list-style-image: url("chrome://global/skin/icons/autocomplete-search.svg#search-icon");
}
richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-title-box > .ac-site-icon {
list-style-image: url("chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted");
}
@media (min-resolution: 2dppx) {
.ac-result-type-bookmark {
list-style-image: url("chrome://browser/skin/places/star-icons@2x.png");

View File

@ -135,6 +135,7 @@
}
/* TITLES */
#newtab-intro-what,
.newtab-sponsored,
.newtab-title {
color: #5c5c5c;

View File

@ -1463,6 +1463,20 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
}
%endif
richlistitem[type~="action"][actiontype="searchengine"] > .ac-title-box > .ac-site-icon {
list-style-image: url("chrome://global/skin/icons/autocomplete-search.svg#search-icon");
}
%ifdef WINDOWS_AERO
@media not all and (-moz-windows-default-theme) {
%endif
richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-title-box > .ac-site-icon {
list-style-image: url("chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted");
}
%ifdef WINDOWS_AERO
}
%endif
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
color: GrayText;
}

View File

@ -6221,13 +6221,13 @@ if test "$OS_ARCH" = "WINNT"; then
else
AC_MSG_RESULT([no])
if test -z "$CROSS_COMPILE"; then
AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS version $REQ_NSIS_MAJOR_VER.$MIN_NSIS_MINOR_VER or greater in your path.])
AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS version $MIN_NSIS_MAJOR_VER.$MIN_NSIS_MINOR_VER or greater in your path.])
else
MAKENSISU=
fi
fi
elif test -z "$CROSS_COMPILE"; then
AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS version $REQ_NSIS_MAJOR_VER.$MIN_NSIS_MINOR_VER or greater in your path.])
AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS version $MIN_NSIS_MAJOR_VER.$MIN_NSIS_MINOR_VER or greater in your path.])
else
MAKENSISU=
fi

View File

@ -36,6 +36,7 @@
#include "mozilla/dom/MobileMessageManager.h"
#include "mozilla/dom/ServiceWorkerContainer.h"
#include "mozilla/dom/Telephony.h"
#include "mozilla/dom/Voicemail.h"
#include "mozilla/Hal.h"
#include "nsISiteSpecificUserAgent.h"
#include "mozilla/ClearOnShutdown.h"
@ -50,7 +51,6 @@
#include "mozilla/dom/IccManager.h"
#include "mozilla/dom/CellBroadcast.h"
#include "mozilla/dom/MobileConnectionArray.h"
#include "mozilla/dom/Voicemail.h"
#endif
#include "nsIIdleObserver.h"
#include "nsIPermissionManager.h"
@ -175,12 +175,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
#ifdef MOZ_B2G_RIL
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
#endif
#ifdef MOZ_B2G_BT
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
@ -251,6 +251,11 @@ Navigator::Invalidate()
mTelephony = nullptr;
}
if (mVoicemail) {
mVoicemail->Shutdown();
mVoicemail = nullptr;
}
if (mConnection) {
mConnection->Shutdown();
mConnection = nullptr;
@ -269,10 +274,6 @@ Navigator::Invalidate()
mIccManager->Shutdown();
mIccManager = nullptr;
}
if (mVoicemail) {
mVoicemail = nullptr;
}
#endif
#ifdef MOZ_B2G_BT
@ -1651,6 +1652,8 @@ Navigator::GetMozCellBroadcast(ErrorResult& aRv)
return mCellBroadcast;
}
#endif // MOZ_B2G_RIL
Voicemail*
Navigator::GetMozVoicemail(ErrorResult& aRv)
{
@ -1660,15 +1663,14 @@ Navigator::GetMozVoicemail(ErrorResult& aRv)
return nullptr;
}
aRv = NS_NewVoicemail(mWindow, getter_AddRefs(mVoicemail));
if (aRv.Failed()) {
return nullptr;
}
mVoicemail = Voicemail::Create(mWindow, aRv);
}
return mVoicemail;
}
#ifdef MOZ_B2G_RIL
IccManager*
Navigator::GetMozIccManager(ErrorResult& aRv)
{

View File

@ -88,11 +88,11 @@ class BluetoothManager;
class CellBroadcast;
class IccManager;
class MobileConnectionArray;
class Voicemail;
#endif
class PowerManager;
class Telephony;
class Voicemail;
namespace time {
class TimeManager;
@ -221,6 +221,7 @@ public:
DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
MobileMessageManager* GetMozMobileMessage();
Telephony* GetMozTelephony(ErrorResult& aRv);
Voicemail* GetMozVoicemail(ErrorResult& aRv);
network::Connection* GetConnection(ErrorResult& aRv);
nsDOMCameraManager* GetMozCameras(ErrorResult& aRv);
void MozSetMessageHandler(const nsAString& aType,
@ -234,7 +235,6 @@ public:
#ifdef MOZ_B2G_RIL
MobileConnectionArray* GetMozMobileConnections(ErrorResult& aRv);
CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
Voicemail* GetMozVoicemail(ErrorResult& aRv);
IccManager* GetMozIccManager(ErrorResult& aRv);
#endif // MOZ_B2G_RIL
#ifdef MOZ_GAMEPAD
@ -331,12 +331,12 @@ private:
nsRefPtr<PowerManager> mPowerManager;
nsRefPtr<MobileMessageManager> mMobileMessageManager;
nsRefPtr<Telephony> mTelephony;
nsRefPtr<Voicemail> mVoicemail;
nsRefPtr<network::Connection> mConnection;
#ifdef MOZ_B2G_RIL
nsRefPtr<MobileConnectionArray> mMobileConnections;
nsRefPtr<CellBroadcast> mCellBroadcast;
nsRefPtr<IccManager> mIccManager;
nsRefPtr<Voicemail> mVoicemail;
#endif
#ifdef MOZ_B2G_BT
nsRefPtr<bluetooth::BluetoothManager> mBluetooth;

View File

@ -755,6 +755,10 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::Voicemail',
},
'MozVoicemailStatus': {
'nativeType': 'mozilla::dom::VoicemailStatus',
},
'MutationObserver': {
'nativeType': 'nsDOMMutationObserver',
},

View File

@ -188,6 +188,12 @@ extern bool gBluetoothDebugFlag;
// Bluetooth stack internal error, such as I/O error
#define ERR_INTERNAL_ERROR "InternalError"
/**
* BT specification v4.1 defines the maximum attribute length as 512 octets.
* Currently use 600 here to conform to bluedroid's BTGATT_MAX_ATTR_LEN.
*/
#define BLUETOOTH_GATT_MAX_ATTR_LEN 600
BEGIN_BLUETOOTH_NAMESPACE
enum BluetoothStatus {
@ -497,6 +503,46 @@ struct BluetoothAvrcpPlayerSettings {
uint8_t mValues[256];
};
struct BluetoothGattAdvData {
uint8_t mAdvData[62];
};
struct BluetoothGattId {
BluetoothUuid mUuid;
uint8_t mInstanceId;
};
struct BluetoothGattServiceId {
BluetoothGattId mId;
uint8_t mIsPrimary;
};
struct BluetoothGattReadParam {
BluetoothGattServiceId mServiceId;
BluetoothGattId mCharId;
BluetoothGattId mDescriptorId;
uint8_t mValue[BLUETOOTH_GATT_MAX_ATTR_LEN];
uint16_t mValueLength;
uint16_t mValueType;
uint8_t mStatus;
};
struct BluetoothGattWriteParam {
BluetoothGattServiceId mServiceId;
BluetoothGattId mCharId;
BluetoothGattId mDescriptorId;
uint8_t mStatus;
};
struct BluetoothGattNotifyParam {
uint8_t mValue[BLUETOOTH_GATT_MAX_ATTR_LEN];
nsString mBdAddr;
BluetoothGattServiceId mServiceId;
BluetoothGattId mCharId;
uint16_t mLength;
uint8_t mIsNotify;
};
END_BLUETOOTH_NAMESPACE
#endif // mozilla_dom_bluetooth_bluetoothcommon_h__

View File

@ -76,6 +76,41 @@ BluetoothAvrcpInterface::BluetoothAvrcpInterface()
BluetoothAvrcpInterface::~BluetoothAvrcpInterface()
{ }
//
// Bluetooth GATT Interface
//
// Notification handling
//
BluetoothGattClientNotificationHandler::~BluetoothGattClientNotificationHandler()
{ }
BluetoothGattServerNotificationHandler::~BluetoothGattServerNotificationHandler()
{ }
BluetoothGattNotificationHandler::~BluetoothGattNotificationHandler()
{ }
// Interface
//
BluetoothGattClientInterface::BluetoothGattClientInterface()
{ }
BluetoothGattClientInterface::~BluetoothGattClientInterface()
{ }
BluetoothGattInterface::BluetoothGattInterface()
{ }
BluetoothGattInterface::~BluetoothGattInterface()
{ }
//
// Bluetooth Core Interface
//
// Notification handling
//

View File

@ -9,6 +9,7 @@
#include "BluetoothCommon.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/TypedArray.h"
BEGIN_BLUETOOTH_NAMESPACE
@ -452,6 +453,351 @@ protected:
virtual ~BluetoothAvrcpInterface();
};
//
// GATT Interface
//
class BluetoothGattClientNotificationHandler
{
public:
virtual ~BluetoothGattClientNotificationHandler();
virtual void
RegisterClientNotification(int aStatus,
int aClientIf,
const BluetoothUuid& aAppUuid)
{ }
virtual void
ScanResultNotification(const nsAString& aBdAddr,
int aRssi,
const BluetoothGattAdvData& aAdvData)
{ }
virtual void
ConnectNotification(int aConnId,
int aStatus,
int aClientIf,
const nsAString& aBdAddr)
{ }
virtual void
DisconnectNotification(int aConnId,
int aStatus,
int aClientIf,
const nsAString& aBdAddr)
{ }
virtual void
SearchCompleteNotification(int aConnId, int aStatus) { }
virtual void
SearchResultNotification(int aConnId,
const BluetoothGattServiceId& aServiceId)
{ }
virtual void
GetCharacteristicNotification(int aConnId,
int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
int aCharProperty)
{ }
virtual void
GetDescriptorNotification(int aConnId,
int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
const BluetoothGattId& aDescriptorId)
{ }
virtual void
GetIncludedServiceNotification(int aConnId,
int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattServiceId& aIncludedServId)
{ }
virtual void
RegisterNotificationNotification(int aConnId,
int aIsRegister,
int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId)
{ }
virtual void
NotifyNotification(int aConnId, const BluetoothGattNotifyParam& aNotifyParam)
{ }
virtual void
ReadCharacteristicNotification(int aConnId,
int aStatus,
const BluetoothGattReadParam& aReadParam)
{ }
virtual void
WriteCharacteristicNotification(int aConnId,
int aStatus,
const BluetoothGattWriteParam& aWriteParam)
{ }
virtual void
ReadDescriptorNotification(int aConnId,
int aStatus,
const BluetoothGattReadParam& aReadParam)
{ }
virtual void
WriteDescriptorNotification(int aConnId,
int aStatus,
const BluetoothGattWriteParam& aWriteParam)
{ }
virtual void
ExecuteWriteNotification(int aConnId, int aStatus) { }
virtual void
ReadRemoteRssiNotification(int aClientIf,
const nsAString& aBdAddr,
int aRssi,
int aStatus)
{ }
virtual void
ListenNotification(int aStatus, int aServerIf) { }
protected:
BluetoothGattClientNotificationHandler()
{ }
};
class BluetoothGattServerNotificationHandler
{
public:
virtual ~BluetoothGattServerNotificationHandler();
// TODO: Add server notifications
protected:
BluetoothGattServerNotificationHandler()
{ }
};
class BluetoothGattNotificationHandler
: public BluetoothGattClientNotificationHandler
, public BluetoothGattServerNotificationHandler
{
public:
virtual ~BluetoothGattNotificationHandler();
protected:
BluetoothGattNotificationHandler()
{ }
};
class BluetoothGattClientResultHandler
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothGattClientResultHandler)
virtual ~BluetoothGattClientResultHandler() { }
virtual void OnError(BluetoothStatus aStatus)
{
BT_WARNING("Received error code %d", (int)aStatus);
}
virtual void RegisterClient() { }
virtual void UnregisterClient() { }
virtual void Scan() { }
virtual void Connect() { }
virtual void Disconnect() { }
virtual void Listen() { }
virtual void Refresh() { }
virtual void SearchService() { }
virtual void GetIncludedService() { }
virtual void GetCharacteristic() { }
virtual void GetDescriptor() { }
virtual void ReadCharacteristic() { }
virtual void WriteCharacteristic() { }
virtual void ReadDescriptor() { }
virtual void WriteDescriptor() { }
virtual void ExecuteWrite() { }
virtual void RegisterNotification() { }
virtual void DeregisterNotification() { }
virtual void ReadRemoteRssi() { }
virtual void GetDeviceType() { }
virtual void SetAdvData() { }
};
// TODO: Add GattServerResultHandler
class BluetoothGattResultHandler
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothGattResultHandler)
virtual ~BluetoothGattResultHandler() { }
virtual void OnError(BluetoothStatus aStatus)
{
BT_WARNING("Received error code %d", (int)aStatus);
}
virtual void Init() { }
virtual void Cleanup() { }
};
class BluetoothGattClientInterface
{
public:
/* Register / Unregister */
virtual void RegisterClient(const BluetoothUuid& aUuid,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void UnregisterClient(int aClientIf,
BluetoothGattClientResultHandler* aRes) = 0;
/* Start / Stop LE Scan */
virtual void Scan(int aClientIf, bool aStart,
BluetoothGattClientResultHandler* aRes) = 0;
/* Connect / Disconnect */
virtual void Connect(int aClientIf,
const nsAString& aBdAddr,
bool aIsDirect, /* auto connect */
BluetoothGattClientResultHandler* aRes) = 0;
virtual void Disconnect(int aClientIf,
const nsAString& aBdAddr,
int aConnId,
BluetoothGattClientResultHandler* aRes) = 0;
/* Start / Stop advertisements to listen for incoming connections */
virtual void Listen(int aClientIf,
bool aIsStart,
BluetoothGattClientResultHandler* aRes) = 0;
/* Clear the attribute cache for a given device*/
virtual void Refresh(int aClientIf,
const nsAString& aBdAddr,
BluetoothGattClientResultHandler* aRes) = 0;
/* Enumerate Attributes */
virtual void SearchService(int aConnId,
const BluetoothUuid& aUuid,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void GetIncludedService(
int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattServiceId& aStartServiceId,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void GetCharacteristic(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aStartCharId,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void GetDescriptor(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
const BluetoothGattId& aDescriptorId,
BluetoothGattClientResultHandler* aRes) = 0;
/* Read / Write An Attribute */
virtual void ReadCharacteristic(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
int aAuthReq,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void WriteCharacteristic(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
int aWriteType,
int aLen,
int aAuthReq,
const ArrayBuffer& aValue,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void ReadDescriptor(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
const BluetoothGattId& aDescriptorId,
int aAuthReq,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void WriteDescriptor(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
const BluetoothGattId& aDescriptorId,
int aWriteType,
int aLen,
int aAuthReq,
const ArrayBuffer& aValue,
BluetoothGattClientResultHandler* aRes) = 0;
/* Execute / Abort Prepared Write*/
virtual void ExecuteWrite(int aConnId,
int aIsExecute,
BluetoothGattClientResultHandler* aRes) = 0;
/* Register / Deregister Characteristic Notifications or Indications */
virtual void RegisterNotification(
int aClientIf,
const nsAString& aBdAddr,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void DeregisterNotification(
int aClientIf,
const nsAString& aBdAddr,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void ReadRemoteRssi(int aClientIf,
const nsAString& aBdAddr,
BluetoothGattClientResultHandler* aRes) = 0;
virtual void GetDeviceType(const nsAString& aBdAddr,
BluetoothGattClientResultHandler* aRes) = 0;
/* Set advertising data or scan response data */
virtual void SetAdvData(int aServerIf,
bool aIsScanRsp,
bool aIsNameIncluded,
bool aIsTxPowerIncluded,
int aMinInterval,
int aMaxInterval,
int aApperance,
uint8_t aManufacturerLen,
const ArrayBuffer& aManufacturerData,
BluetoothGattClientResultHandler* aRes) = 0;
protected:
BluetoothGattClientInterface();
virtual ~BluetoothGattClientInterface();
};
// TODO: Add GattServerInterface
class BluetoothGattInterface
{
public:
virtual void Init(BluetoothGattNotificationHandler* aNotificationHandler,
BluetoothGattResultHandler* aRes) = 0;
virtual void Cleanup(BluetoothGattResultHandler* aRes) = 0;
virtual BluetoothGattClientInterface* GetBluetoothGattClientInterface() = 0;
protected:
BluetoothGattInterface();
virtual ~BluetoothGattInterface();
};
//
// Bluetooth Core Interface
//
@ -625,6 +971,7 @@ public:
virtual BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() = 0;
virtual BluetoothA2dpInterface* GetBluetoothA2dpInterface() = 0;
virtual BluetoothAvrcpInterface* GetBluetoothAvrcpInterface() = 0;
virtual BluetoothGattInterface* GetBluetoothGattInterface() = 0;
protected:
BluetoothInterface();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,186 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* 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_bluetooth_bluedroid_bluetoothgatthalinterface_h__
#define mozilla_dom_bluetooth_bluedroid_bluetoothgatthalinterface_h__
#include <hardware/bluetooth.h>
#if ANDROID_VERSION >= 19
#include <hardware/bt_gatt.h>
#endif
#include "BluetoothCommon.h"
#include "BluetoothInterface.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothHALInterface;
class BluetoothGattClientHALInterface MOZ_FINAL
: public BluetoothGattClientInterface
{
public:
friend class BluetoothGattHALInterface;
/* Register / Unregister */
void RegisterClient(const BluetoothUuid& aUuid,
BluetoothGattClientResultHandler* aRes);
void UnregisterClient(int aClientIf,
BluetoothGattClientResultHandler* aRes);
/* Start / Stop LE Scan */
void Scan(int aClientIf, bool aStart,
BluetoothGattClientResultHandler* aRes);
/* Connect / Disconnect */
void Connect(int aClientIf,
const nsAString& aBdAddr,
bool aIsDirect, /* auto connect */
BluetoothGattClientResultHandler* aRes);
void Disconnect(int aClientIf,
const nsAString& aBdAddr,
int aConnId,
BluetoothGattClientResultHandler* aRes);
/* Start / Stop advertisements to listen for incoming connections */
void Listen(int aClientIf,
bool aIsStart,
BluetoothGattClientResultHandler* aRes);
/* Clear the attribute cache for a given device*/
void Refresh(int aClientIf,
const nsAString& aBdAddr,
BluetoothGattClientResultHandler* aRes);
/* Enumerate Attributes */
void SearchService(int aConnId,
const BluetoothUuid& aUuid,
BluetoothGattClientResultHandler* aRes);
void GetIncludedService(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattServiceId& aStartServiceId,
BluetoothGattClientResultHandler* aRes);
void GetCharacteristic(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aStartCharId,
BluetoothGattClientResultHandler* aRes);
void GetDescriptor(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
const BluetoothGattId& aDescriptorId,
BluetoothGattClientResultHandler* aRes);
/* Read / Write An Attribute */
void ReadCharacteristic(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
int aAuthReq,
BluetoothGattClientResultHandler* aRes);
void WriteCharacteristic(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
int aWriteType,
int aLen,
int aAuthReq,
const ArrayBuffer& aValue,
BluetoothGattClientResultHandler* aRes);
void ReadDescriptor(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
const BluetoothGattId& aDescriptorId,
int aAuthReq,
BluetoothGattClientResultHandler* aRes);
void WriteDescriptor(int aConnId,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
const BluetoothGattId& aDescriptorId,
int aWriteType,
int aLen,
int aAuthReq,
const ArrayBuffer& aValue,
BluetoothGattClientResultHandler* aRes);
/* Execute / Abort Prepared Write*/
void ExecuteWrite(int aConnId,
int aIsExecute,
BluetoothGattClientResultHandler* aRes);
/* Register / Deregister Characteristic Notifications or Indications */
void RegisterNotification(int aClientIf,
const nsAString& aBdAddr,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
BluetoothGattClientResultHandler* aRes);
void DeregisterNotification(int aClientIf,
const nsAString& aBdAddr,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
BluetoothGattClientResultHandler* aRes);
void ReadRemoteRssi(int aClientIf,
const nsAString& aBdAddr,
BluetoothGattClientResultHandler* aRes);
void GetDeviceType(const nsAString& aBdAddr,
BluetoothGattClientResultHandler* aRes);
/* Set advertising data or scan response data */
void SetAdvData(int aServerIf,
bool aIsScanRsp,
bool aIsNameIncluded,
bool aIsTxPowerIncluded,
int aMinInterval,
int aMaxInterval,
int aApperance,
uint8_t aManufacturerLen,
const ArrayBuffer& aManufacturerData,
BluetoothGattClientResultHandler* aRes);
protected:
BluetoothGattClientHALInterface(
#if ANDROID_VERSION >= 19
const btgatt_client_interface_t* aInterface
#endif
);
~BluetoothGattClientHALInterface();
private:
#if ANDROID_VERSION >= 19
const btgatt_client_interface_t* mInterface;
#endif
};
// TODO: Add server interface
class BluetoothGattHALInterface MOZ_FINAL
: public BluetoothGattInterface
{
public:
friend class BluetoothHALInterface;
void Init(BluetoothGattNotificationHandler* aNotificationHandler,
BluetoothGattResultHandler* aRes);
void Cleanup(BluetoothGattResultHandler* aRes);
BluetoothGattClientInterface* GetBluetoothGattClientInterface();
protected:
BluetoothGattHALInterface(
#if ANDROID_VERSION >= 19
const btgatt_interface_t* aInterface
#endif
);
~BluetoothGattHALInterface();
private:
#if ANDROID_VERSION >= 19
const btgatt_interface_t* mInterface;
#endif
};
END_BLUETOOTH_NAMESPACE
#endif

View File

@ -0,0 +1,321 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* 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 "BluetoothGattManager.h"
#include "BluetoothCommon.h"
#include "BluetoothUtils.h"
#include "BluetoothInterface.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "MainThreadUtils.h"
#include "nsIObserverService.h"
#include "nsThreadUtils.h"
using namespace mozilla;
USING_BLUETOOTH_NAMESPACE
namespace {
StaticRefPtr<BluetoothGattManager> sBluetoothGattManager;
static BluetoothGattInterface* sBluetoothGattInterface;
static BluetoothGattClientInterface* sBluetoothGattClientInterface;
} // anonymous namespace
bool BluetoothGattManager::mInShutdown = false;
/*
* Static functions
*/
BluetoothGattManager*
BluetoothGattManager::Get()
{
MOZ_ASSERT(NS_IsMainThread());
// If sBluetoothGattManager already exists, exit early
if (sBluetoothGattManager) {
return sBluetoothGattManager;
}
// If we're in shutdown, don't create a new instance
NS_ENSURE_FALSE(mInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothGattManager* manager = new BluetoothGattManager();
sBluetoothGattManager = manager;
return sBluetoothGattManager;
}
class InitGattResultHandler MOZ_FINAL : public BluetoothGattResultHandler
{
public:
InitGattResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
{
BT_WARNING("BluetoothGattInterface::Init failed: %d",
(int)aStatus);
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Init() MOZ_OVERRIDE
{
if (mRes) {
mRes->Init();
}
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
// static
void
BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
{
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
if (!btInf) {
BT_LOGR("Error: Bluetooth interface not available");
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
}
return;
}
sBluetoothGattInterface = btInf->GetBluetoothGattInterface();
if (!sBluetoothGattInterface) {
BT_LOGR("Error: Bluetooth GATT interface not available");
if (aRes) {
aRes->OnError(NS_ERROR_FAILURE);
}
return;
}
sBluetoothGattClientInterface =
sBluetoothGattInterface->GetBluetoothGattClientInterface();
NS_ENSURE_TRUE_VOID(sBluetoothGattClientInterface);
BluetoothGattManager* gattManager = BluetoothGattManager::Get();
sBluetoothGattInterface->Init(gattManager,
new InitGattResultHandler(aRes));
}
class CleanupResultHandler MOZ_FINAL : public BluetoothGattResultHandler
{
public:
CleanupResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
{
BT_WARNING("BluetoothGattInterface::Cleanup failed: %d",
(int)aStatus);
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
}
void Cleanup() MOZ_OVERRIDE
{
sBluetoothGattClientInterface = nullptr;
sBluetoothGattInterface = nullptr;
if (mRes) {
mRes->Deinit();
}
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
class CleanupResultHandlerRunnable MOZ_FINAL : public nsRunnable
{
public:
CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{
MOZ_ASSERT(mRes);
}
NS_IMETHOD Run() MOZ_OVERRIDE
{
mRes->Deinit();
return NS_OK;
}
private:
nsRefPtr<BluetoothProfileResultHandler> mRes;
};
// static
void
BluetoothGattManager::DeinitGattInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sBluetoothGattInterface) {
sBluetoothGattInterface->Cleanup(new CleanupResultHandler(aRes));
} else if (aRes) {
// We dispatch a runnable here to make the profile resource handler
// behave as if GATT was initialized.
nsRefPtr<nsRunnable> r = new CleanupResultHandlerRunnable(aRes);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
}
}
}
//
// Notification Handlers
//
void
BluetoothGattManager::RegisterClientNotification(int aStatus,
int aClientIf,
const BluetoothUuid& aAppUuid)
{ }
void
BluetoothGattManager::ScanResultNotification(
const nsAString& aBdAddr, int aRssi,
const BluetoothGattAdvData& aAdvData)
{ }
void
BluetoothGattManager::ConnectNotification(int aConnId,
int aStatus,
int aClientIf,
const nsAString& aBdAddr)
{ }
void
BluetoothGattManager::DisconnectNotification(int aConnId,
int aStatus,
int aClientIf,
const nsAString& aBdAddr)
{ }
void
BluetoothGattManager::SearchCompleteNotification(int aConnId, int aStatus)
{ }
void
BluetoothGattManager::SearchResultNotification(
int aConnId, const BluetoothGattServiceId& aServiceId)
{ }
void
BluetoothGattManager::GetCharacteristicNotification(
int aConnId, int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
int aCharProperty)
{ }
void
BluetoothGattManager::GetDescriptorNotification(
int aConnId, int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
const BluetoothGattId& aDescriptorId)
{ }
void
BluetoothGattManager::GetIncludedServiceNotification(
int aConnId, int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattServiceId& aIncludedServId)
{ }
void
BluetoothGattManager::RegisterNotificationNotification(
int aConnId, int aIsRegister, int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId)
{ }
void
BluetoothGattManager::NotifyNotification(
int aConnId, const BluetoothGattNotifyParam& aNotifyParam)
{ }
void
BluetoothGattManager::ReadCharacteristicNotification(
int aConnId, int aStatus, const BluetoothGattReadParam& aReadParam)
{ }
void
BluetoothGattManager::WriteCharacteristicNotification(
int aConnId, int aStatus, const BluetoothGattWriteParam& aWriteParam)
{ }
void
BluetoothGattManager::ReadDescriptorNotification(
int aConnId, int aStatus, const BluetoothGattReadParam& aReadParam)
{ }
void
BluetoothGattManager::WriteDescriptorNotification(
int aConnId, int aStatus, const BluetoothGattWriteParam& aWriteParam)
{ }
void
BluetoothGattManager::ExecuteWriteNotification(int aConnId, int aStatus)
{ }
void
BluetoothGattManager::ReadRemoteRssiNotification(int aClientIf,
const nsAString& aBdAddr,
int aRssi,
int aStatus)
{ }
void
BluetoothGattManager::ListenNotification(int aStatus,
int aServerIf)
{ }
BluetoothGattManager::BluetoothGattManager()
{ }
BluetoothGattManager::~BluetoothGattManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
}
NS_IMETHODIMP
BluetoothGattManager::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(sBluetoothGattManager);
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
HandleShutdown();
return NS_OK;
}
MOZ_ASSERT(false, "BluetoothGattManager got unexpected topic!");
return NS_ERROR_UNEXPECTED;
}
void
BluetoothGattManager::HandleShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
mInShutdown = true;
sBluetoothGattManager = nullptr;
}
NS_IMPL_ISUPPORTS(BluetoothGattManager, nsIObserver)

View File

@ -0,0 +1,115 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* 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_bluetooth_bluetoothgattmanager_h__
#define mozilla_dom_bluetooth_bluetoothgattmanager_h__
#include "BluetoothCommon.h"
#include "BluetoothInterface.h"
#include "BluetoothProfileManagerBase.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothGattManager MOZ_FINAL : public nsIObserver
, public BluetoothGattNotificationHandler
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static BluetoothGattManager* Get();
static void InitGattInterface(BluetoothProfileResultHandler* aRes);
static void DeinitGattInterface(BluetoothProfileResultHandler* aRes);
virtual ~BluetoothGattManager();
private:
BluetoothGattManager();
void HandleShutdown();
void RegisterClientNotification(int aStatus,
int aClientIf,
const BluetoothUuid& aAppUuid) MOZ_OVERRIDE;
void ScanResultNotification(
const nsAString& aBdAddr, int aRssi,
const BluetoothGattAdvData& aAdvData) MOZ_OVERRIDE;
void ConnectNotification(int aConnId,
int aStatus,
int aClientIf,
const nsAString& aBdAddr) MOZ_OVERRIDE;
void DisconnectNotification(int aConnId,
int aStatus,
int aClientIf,
const nsAString& aBdAddr) MOZ_OVERRIDE;
void SearchCompleteNotification(int aConnId, int aStatus) MOZ_OVERRIDE;
void SearchResultNotification(int aConnId,
const BluetoothGattServiceId& aServiceId)
MOZ_OVERRIDE;
void GetCharacteristicNotification(
int aConnId, int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
int aCharProperty) MOZ_OVERRIDE;
void GetDescriptorNotification(
int aConnId, int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId,
const BluetoothGattId& aDescriptorId) MOZ_OVERRIDE;
void GetIncludedServiceNotification(
int aConnId, int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattServiceId& aIncludedServId) MOZ_OVERRIDE;
void RegisterNotificationNotification(
int aConnId, int aIsRegister, int aStatus,
const BluetoothGattServiceId& aServiceId,
const BluetoothGattId& aCharId) MOZ_OVERRIDE;
void NotifyNotification(int aConnId,
const BluetoothGattNotifyParam& aNotifyParam)
MOZ_OVERRIDE;
void ReadCharacteristicNotification(int aConnId,
int aStatus,
const BluetoothGattReadParam& aReadParam)
MOZ_OVERRIDE;
void WriteCharacteristicNotification(
int aConnId, int aStatus,
const BluetoothGattWriteParam& aWriteParam) MOZ_OVERRIDE;
void ReadDescriptorNotification(int aConnId,
int aStatus,
const BluetoothGattReadParam& aReadParam)
MOZ_OVERRIDE;
void WriteDescriptorNotification(int aConnId,
int aStatus,
const BluetoothGattWriteParam& aWriteParam)
MOZ_OVERRIDE;
void ExecuteWriteNotification(int aConnId, int aStatus) MOZ_OVERRIDE;
void ReadRemoteRssiNotification(int aClientIf,
const nsAString& aBdAddr,
int aRssi,
int aStatus) MOZ_OVERRIDE;
void ListenNotification(int aStatus, int aServerIf) MOZ_OVERRIDE;
static bool mInShutdown;
};
END_BLUETOOTH_NAMESPACE
#endif

View File

@ -122,6 +122,18 @@ Convert(const bt_uuid_t& aIn, BluetoothUuid& aOut)
return NS_OK;
}
nsresult
Convert(const BluetoothUuid& aIn, bt_uuid_t& aOut)
{
if (sizeof(aIn.mUuid) != sizeof(aOut.uu)) {
return NS_ERROR_ILLEGAL_VALUE;
}
memcpy(aOut.uu, aIn.mUuid, sizeof(aOut.uu));
return NS_OK;
}
nsresult
Convert(const nsAString& aIn, bt_pin_code_t& aOut)
{
@ -211,6 +223,112 @@ Convert(const btrc_player_settings_t& aIn, BluetoothAvrcpPlayerSettings& aOut)
}
#endif // ANDROID_VERSION >= 18
nsresult
Convert(const uint8_t* aIn, BluetoothGattAdvData& aOut)
{
memcpy(aOut.mAdvData, aIn, sizeof(aOut.mAdvData));
return NS_OK;
}
#if ANDROID_VERSION >= 19
nsresult
Convert(const BluetoothGattId& aIn, btgatt_gatt_id_t& aOut)
{
aOut.inst_id = aIn.mInstanceId;
return Convert(aIn.mUuid, aOut.uuid);
}
nsresult
Convert(const btgatt_gatt_id_t& aIn, BluetoothGattId& aOut)
{
aOut.mInstanceId = aIn.inst_id;
return Convert(aIn.uuid, aOut.mUuid);
}
nsresult
Convert(const BluetoothGattServiceId& aIn, btgatt_srvc_id_t& aOut)
{
aOut.is_primary = aIn.mIsPrimary;
return Convert(aIn.mId, aOut.id);
}
nsresult
Convert(const btgatt_srvc_id_t& aIn, BluetoothGattServiceId& aOut)
{
aOut.mIsPrimary = aIn.is_primary;
return Convert(aIn.id, aOut.mId);
}
nsresult
Convert(const btgatt_read_params_t& aIn, BluetoothGattReadParam& aOut)
{
nsresult rv;
rv = Convert(aIn.srvc_id, aOut.mServiceId);
NS_ENSURE_SUCCESS(rv, rv);
rv = Convert(aIn.char_id, aOut.mCharId);
NS_ENSURE_SUCCESS(rv, rv);
rv = Convert(aIn.descr_id, aOut.mDescriptorId);
NS_ENSURE_SUCCESS(rv, rv);
memcpy(aOut.mValue, aIn.value.value, aIn.value.len);
aOut.mValueLength = aIn.value.len;
aOut.mValueType = aIn.value_type;
aOut.mStatus = aIn.status;
return NS_OK;
}
nsresult
Convert(const btgatt_write_params_t& aIn, BluetoothGattWriteParam& aOut)
{
nsresult rv;
rv = Convert(aIn.srvc_id, aOut.mServiceId);
NS_ENSURE_SUCCESS(rv, rv);
rv = Convert(aIn.char_id, aOut.mCharId);
NS_ENSURE_SUCCESS(rv, rv);
rv = Convert(aIn.descr_id, aOut.mDescriptorId);
NS_ENSURE_SUCCESS(rv, rv);
aOut.mStatus = aIn.status;
return NS_OK;
}
nsresult
Convert(const btgatt_notify_params_t& aIn, BluetoothGattNotifyParam& aOut)
{
nsresult rv;
rv = Convert(aIn.bda, aOut.mBdAddr);
NS_ENSURE_SUCCESS(rv, rv);
rv = Convert(aIn.srvc_id, aOut.mServiceId);
NS_ENSURE_SUCCESS(rv, rv);
rv = Convert(aIn.char_id, aOut.mCharId);
NS_ENSURE_SUCCESS(rv, rv);
memcpy(aOut.mValue, aIn.value, aIn.len);
aOut.mLength = aIn.len;
aOut.mIsNotify = aIn.is_notify;
return NS_OK;
}
#endif // ANDROID_VERSION >= 19
nsresult
Convert(const ArrayBuffer& aIn, char* aOut) {
aIn.ComputeLengthAndData();
memcpy(aOut, aIn.Data(), aIn.Length());
return NS_OK;
}
nsresult
Convert(const bt_property_t& aIn, BluetoothProperty& aOut)
{

View File

@ -14,9 +14,13 @@
#if ANDROID_VERSION >= 18
#include <hardware/bt_rc.h>
#endif
#if ANDROID_VERSION >= 19
#include <hardware/bt_gatt.h>
#endif
#include "BluetoothCommon.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/TypedArray.h"
#include "nsThreadUtils.h"
BEGIN_BLUETOOTH_NAMESPACE
@ -141,6 +145,9 @@ Convert(const uint8_t aIn[16], bt_uuid_t& aOut);
nsresult
Convert(const bt_uuid_t& aIn, BluetoothUuid& aOut);
nsresult
Convert(const BluetoothUuid& aIn, bt_uuid_t& aOut);
nsresult
Convert(const nsAString& aIn, bt_pin_code_t& aOut);
@ -754,6 +761,35 @@ Convert(btrc_remote_features_t aIn, unsigned long& aOut)
}
#endif // ANDROID_VERSION >= 19
nsresult
Convert(const uint8_t* aIn, BluetoothGattAdvData& aOut);
#if ANDROID_VERSION >= 19
nsresult
Convert(const BluetoothGattId& aIn, btgatt_gatt_id_t& aOut);
nsresult
Convert(const btgatt_gatt_id_t& aIn, BluetoothGattId& aOut);
nsresult
Convert(const BluetoothGattServiceId& aIn, btgatt_srvc_id_t& aOut);
nsresult
Convert(const btgatt_srvc_id_t& aIn, BluetoothGattServiceId& aOut);
nsresult
Convert(const btgatt_read_params_t& aIn, BluetoothGattReadParam& aOut);
nsresult
Convert(const btgatt_write_params_t& aIn, BluetoothGattWriteParam& aOut);
nsresult
Convert(const btgatt_notify_params_t& aIn, BluetoothGattNotifyParam& aOut);
#endif // ANDROID_VERSION >= 19
nsresult
Convert(const ArrayBuffer& aIn, char* aOut);
/* |ConvertArray| is a helper for converting arrays. Pass an
* instance of this structure as the first argument to |Convert|
* to convert an array. The output type has to support the array

View File

@ -8,6 +8,7 @@
#include "BluetoothHALHelpers.h"
#include "BluetoothA2dpHALInterface.h"
#include "BluetoothAvrcpHALInterface.h"
#include "BluetoothGattHALInterface.h"
#include "BluetoothHandsfreeHALInterface.h"
#include "BluetoothSocketHALInterface.h"
@ -63,6 +64,19 @@ struct interface_traits<BluetoothAvrcpHALInterface>
};
#endif
#if ANDROID_VERSION >= 19
template<>
struct interface_traits<BluetoothGattHALInterface>
{
typedef const btgatt_interface_t const_interface_type;
static const char* profile_id()
{
return BT_PROFILE_GATT_ID;
}
};
#endif
typedef
BluetoothHALInterfaceRunnable0<BluetoothResultHandler, void>
BluetoothHALResultRunnable;
@ -873,6 +887,22 @@ BluetoothHALInterface::CreateProfileInterface<BluetoothAvrcpHALInterface>()
}
#endif
#if ANDROID_VERSION < 19
/*
* Versions that we don't support GATT will call this function
* to create an GATT interface. All interface methods will fail with
* the error constant STATUS_UNSUPPORTED.
*/
template <>
BluetoothGattHALInterface*
BluetoothHALInterface::CreateProfileInterface<BluetoothGattHALInterface>()
{
BT_WARNING("Bluetooth profile 'gatt' is not supported");
return new BluetoothGattHALInterface();
}
#endif
template <class T>
T*
BluetoothHALInterface::GetProfileInterface()
@ -912,4 +942,10 @@ BluetoothHALInterface::GetBluetoothAvrcpInterface()
return GetProfileInterface<BluetoothAvrcpHALInterface>();
}
BluetoothGattInterface*
BluetoothHALInterface::GetBluetoothGattInterface()
{
return GetProfileInterface<BluetoothGattHALInterface>();
}
END_BLUETOOTH_NAMESPACE

View File

@ -90,6 +90,7 @@ public:
BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface();
BluetoothA2dpInterface* GetBluetoothA2dpInterface();
BluetoothAvrcpInterface* GetBluetoothAvrcpInterface();
BluetoothGattInterface* GetBluetoothGattInterface();
protected:
BluetoothHALInterface(const bt_interface_t* aInterface);

View File

@ -19,6 +19,7 @@
#include "BluetoothServiceBluedroid.h"
#include "BluetoothA2dpManager.h"
#include "BluetoothGattManager.h"
#include "BluetoothHfpManager.h"
#include "BluetoothOppManager.h"
#include "BluetoothProfileController.h"
@ -167,7 +168,8 @@ public:
{
static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = {
BluetoothHfpManager::DeinitHfpInterface,
BluetoothA2dpManager::DeinitA2dpInterface
BluetoothA2dpManager::DeinitA2dpInterface,
BluetoothGattManager::DeinitGattInterface
};
MOZ_ASSERT(NS_IsMainThread());
@ -304,7 +306,8 @@ public:
{
static void (* const sInitManager[])(BluetoothProfileResultHandler*) = {
BluetoothHfpManager::InitHfpInterface,
BluetoothA2dpManager::InitA2dpInterface
BluetoothA2dpManager::InitA2dpInterface,
BluetoothGattManager::InitGattInterface
};
MOZ_ASSERT(NS_IsMainThread());

View File

@ -51,6 +51,8 @@ if CONFIG['MOZ_B2G_BT']:
'bluedroid/BluetoothA2dpHALInterface.cpp',
'bluedroid/BluetoothA2dpManager.cpp',
'bluedroid/BluetoothAvrcpHALInterface.cpp',
'bluedroid/BluetoothGattHALInterface.cpp',
'bluedroid/BluetoothGattManager.cpp',
'bluedroid/BluetoothHALHelpers.cpp',
'bluedroid/BluetoothHALInterface.cpp',
'bluedroid/BluetoothHandsfreeHALInterface.cpp',

View File

@ -66,6 +66,7 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl, DOMMediaStream,
mOnRecorderStateChangeCb,
mOnPreviewStateChangeCb,
mOnAutoFocusMovingCb,
mOnAutoFocusCompletedCb,
mOnFacesDetectedCb)
/* static */
@ -155,6 +156,7 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
, mOnRecorderStateChangeCb(nullptr)
, mOnPreviewStateChangeCb(nullptr)
, mOnAutoFocusMovingCb(nullptr)
, mOnAutoFocusCompletedCb(nullptr)
, mOnFacesDetectedCb(nullptr)
, mWindow(aWindow)
{
@ -618,6 +620,17 @@ nsDOMCameraControl::SetOnAutoFocusMoving(CameraAutoFocusMovingCallback* aCb)
mOnAutoFocusMovingCb = aCb;
}
CameraAutoFocusCallback*
nsDOMCameraControl::GetOnAutoFocusCompleted()
{
return mOnAutoFocusCompletedCb;
}
void
nsDOMCameraControl::SetOnAutoFocusCompleted(CameraAutoFocusCallback* aCb)
{
mOnAutoFocusCompletedCb = aCb;
}
CameraFaceDetectionCallback*
nsDOMCameraControl::GetOnFacesDetected()
{
@ -971,6 +984,7 @@ nsDOMCameraControl::Shutdown()
mOnRecorderStateChangeCb = nullptr;
mOnPreviewStateChangeCb = nullptr;
mOnAutoFocusMovingCb = nullptr;
mOnAutoFocusCompletedCb = nullptr;
mOnFacesDetectedCb = nullptr;
mCameraControl->Shutdown();
@ -1166,6 +1180,12 @@ nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
ErrorResult ignored;
cb->Call(aAutoFocusSucceeded, ignored);
}
cb = mOnAutoFocusCompletedCb;
if (cb) {
ErrorResult ignored;
cb->Call(aAutoFocusSucceeded, ignored);
}
}
void

View File

@ -96,6 +96,8 @@ public:
void SetOnPreviewStateChange(dom::CameraPreviewStateChange* aCb);
dom::CameraAutoFocusMovingCallback* GetOnAutoFocusMoving();
void SetOnAutoFocusMoving(dom::CameraAutoFocusMovingCallback* aCb);
dom::CameraAutoFocusCallback* GetOnAutoFocusCompleted();
void SetOnAutoFocusCompleted(dom::CameraAutoFocusCallback* aCb);
dom::CameraFaceDetectionCallback* GetOnFacesDetected();
void SetOnFacesDetected(dom::CameraFaceDetectionCallback* aCb);
@ -208,6 +210,7 @@ protected:
nsRefPtr<dom::CameraRecorderStateChange> mOnRecorderStateChangeCb;
nsRefPtr<dom::CameraPreviewStateChange> mOnPreviewStateChangeCb;
nsRefPtr<dom::CameraAutoFocusMovingCallback> mOnAutoFocusMovingCb;
nsRefPtr<dom::CameraAutoFocusCallback> mOnAutoFocusCompletedCb;
nsRefPtr<dom::CameraFaceDetectionCallback> mOnFacesDetectedCb;
// Camera event listener; we only need this weak reference so that

View File

@ -35,8 +35,10 @@ var Camera = {
firstCallFailed: false,
secondCallSucceeded: false,
callbackTriggered: false,
checkForDone: function test_checkForDone() {
if (Camera.firstCallFailed && Camera.secondCallSucceeded) {
ok(Camera.callbackTriggered, "Async callback triggered");
Camera.cameraObj.release();
Camera.cameraObj = null;
CameraTest.end();
@ -60,6 +62,9 @@ var Camera = {
failureTwo: function test_failureTwo(error) {
ok(false, "Second call to autoFocus() failed unexpectedly with: " + error);
},
callback: function test_callback(focused) {
Camera.callbackTriggered = true;
},
start: function test_start() {
function onSuccess(camera, config) {
@ -69,6 +74,7 @@ var Camera = {
// It doesn't matter if the emulator supports focus or not;
// this is just testing the sequencing.
camera.onAutoFocusCompleted = Camera.callback;
camera.autoFocus(Camera.successOne, Camera.failureOne);
camera.autoFocus(Camera.successTwo, Camera.failureTwo);
};

View File

@ -153,6 +153,7 @@
#include "mozilla/dom/DataStoreService.h"
#include "mozilla/dom/telephony/PTelephonyChild.h"
#include "mozilla/dom/time/DateCacheCleaner.h"
#include "mozilla/dom/voicemail/VoicemailIPCService.h"
#include "mozilla/net/NeckoMessageUtils.h"
#include "mozilla/RemoteSpellCheckEngineChild.h"
@ -166,6 +167,7 @@ using namespace mozilla::dom::mobileconnection;
using namespace mozilla::dom::mobilemessage;
using namespace mozilla::dom::indexedDB;
using namespace mozilla::dom::telephony;
using namespace mozilla::dom::voicemail;
using namespace mozilla::hal_sandbox;
using namespace mozilla::ipc;
using namespace mozilla::layers;
@ -1416,6 +1418,30 @@ ContentChild::DeallocPTelephonyChild(PTelephonyChild* aActor)
return true;
}
PVoicemailChild*
ContentChild::AllocPVoicemailChild()
{
MOZ_CRASH("No one should be allocating PVoicemailChild actors");
}
PVoicemailChild*
ContentChild::SendPVoicemailConstructor(PVoicemailChild* aActor)
{
aActor = PContentChild::SendPVoicemailConstructor(aActor);
if (aActor) {
static_cast<VoicemailIPCService*>(aActor)->AddRef();
}
return aActor;
}
bool
ContentChild::DeallocPVoicemailChild(PVoicemailChild* aActor)
{
static_cast<VoicemailIPCService*>(aActor)->Release();
return true;
}
PStorageChild*
ContentChild::AllocPStorageChild()
{

View File

@ -233,6 +233,10 @@ public:
virtual PTelephonyChild* AllocPTelephonyChild() MOZ_OVERRIDE;
virtual bool DeallocPTelephonyChild(PTelephonyChild*) MOZ_OVERRIDE;
virtual PVoicemailChild* AllocPVoicemailChild() MOZ_OVERRIDE;
PVoicemailChild* SendPVoicemailConstructor(PVoicemailChild* aActor);
virtual bool DeallocPVoicemailChild(PVoicemailChild*) MOZ_OVERRIDE;
virtual PStorageChild* AllocPStorageChild() MOZ_OVERRIDE;
virtual bool DeallocPStorageChild(PStorageChild* aActor) MOZ_OVERRIDE;

View File

@ -53,6 +53,7 @@
#include "mozilla/dom/mobilemessage/SmsParent.h"
#include "mozilla/dom/telephony/TelephonyParent.h"
#include "mozilla/dom/time/DateCacheCleaner.h"
#include "mozilla/dom/voicemail/VoicemailParent.h"
#include "mozilla/hal_sandbox/PHalParent.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundParent.h"
@ -196,6 +197,7 @@ using namespace mozilla::dom::power;
using namespace mozilla::dom::mobileconnection;
using namespace mozilla::dom::mobilemessage;
using namespace mozilla::dom::telephony;
using namespace mozilla::dom::voicemail;
using namespace mozilla::hal;
using namespace mozilla::ipc;
using namespace mozilla::layers;
@ -3160,6 +3162,31 @@ ContentParent::DeallocPTelephonyParent(PTelephonyParent* aActor)
return true;
}
PVoicemailParent*
ContentParent::AllocPVoicemailParent()
{
if (!AssertAppProcessPermission(this, "voicemail")) {
return nullptr;
}
VoicemailParent* actor = new VoicemailParent();
actor->AddRef();
return actor;
}
bool
ContentParent::RecvPVoicemailConstructor(PVoicemailParent* aActor)
{
return static_cast<VoicemailParent*>(aActor)->Init();
}
bool
ContentParent::DeallocPVoicemailParent(PVoicemailParent* aActor)
{
static_cast<VoicemailParent*>(aActor)->Release();
return true;
}
PStorageParent*
ContentParent::AllocPStorageParent()
{

View File

@ -487,6 +487,10 @@ private:
virtual PTelephonyParent* AllocPTelephonyParent() MOZ_OVERRIDE;
virtual bool DeallocPTelephonyParent(PTelephonyParent*) MOZ_OVERRIDE;
virtual PVoicemailParent* AllocPVoicemailParent() MOZ_OVERRIDE;
virtual bool RecvPVoicemailConstructor(PVoicemailParent* aActor) MOZ_OVERRIDE;
virtual bool DeallocPVoicemailParent(PVoicemailParent* aActor) MOZ_OVERRIDE;
virtual bool DeallocPStorageParent(PStorageParent* aActor) MOZ_OVERRIDE;
virtual PBluetoothParent* AllocPBluetoothParent() MOZ_OVERRIDE;

View File

@ -31,6 +31,7 @@ include protocol PSpeechSynthesis;
include protocol PStorage;
include protocol PTelephony;
include protocol PTestShell;
include protocol PVoicemail;
include protocol PJavaScript;
include protocol PRemoteSpellcheckEngine;
include DOMTypes;
@ -338,6 +339,7 @@ intr protocol PContent
manages PStorage;
manages PTelephony;
manages PTestShell;
manages PVoicemail;
manages PJavaScript;
manages PRemoteSpellcheckEngine;
@ -539,6 +541,8 @@ parent:
PTelephony();
PVoicemail();
PBluetooth();
PFMRadio();

View File

@ -90,6 +90,7 @@ DIRS += [
'promise',
'smil',
'telephony',
'voicemail',
'inputmethod',
'webidl',
'xbl',
@ -112,7 +113,6 @@ if CONFIG['MOZ_B2G_RIL']:
DIRS += [
'icc',
'cellbroadcast',
'voicemail',
'wappush',
]

View File

@ -33,7 +33,6 @@ const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
const kPrefVoicemailDefaultServiceId = "dom.voicemail.defaultServiceId";
let DEBUG;
function debug(s) {
@ -48,8 +47,6 @@ const GSMICCINFO_CID =
Components.ID("{e0fa785b-ad3f-46ed-bc56-fcb0d6fe4fa8}");
const CDMAICCINFO_CID =
Components.ID("{3d1f844f-9ec5-48fb-8907-aed2e5421709}");
const VOICEMAILSTATUS_CID=
Components.ID("{5467f2eb-e214-43ea-9b89-67711241ec8e}");
const CELLBROADCASTMESSAGE_CID =
Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
const CELLBROADCASTETWSINFO_CID =
@ -60,8 +57,6 @@ const ICCCARDLOCKERROR_CID =
const RIL_IPC_MSG_NAMES = [
"RIL:CardStateChanged",
"RIL:IccInfoChanged",
"RIL:VoicemailNotification",
"RIL:VoicemailInfoChanged",
"RIL:CardLockResult",
"RIL:CardLockRetryCount",
"RIL:StkCommand",
@ -173,27 +168,6 @@ CdmaIccInfo.prototype = {
prlVersion: 0
};
function VoicemailInfo() {}
VoicemailInfo.prototype = {
number: null,
displayName: null
};
function VoicemailStatus(clientId) {
this.serviceId = clientId;
}
VoicemailStatus.prototype = {
QueryInterface: XPCOMUtils.generateQI([]),
classID: VOICEMAILSTATUS_CID,
contractID: "@mozilla.org/voicemailstatus;1",
serviceId: -1,
hasMessages: false,
messageCount: -1, // Count unknown.
returnNumber: null,
returnMessage: null
};
function CellBroadcastMessage(clientId, pdu) {
this.serviceId = clientId;
this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope];
@ -280,36 +254,27 @@ function RILContentHelper() {
if (DEBUG) debug("Number of clients: " + this.numClients);
this.rilContexts = [];
this.voicemailInfos = [];
this.voicemailStatuses = [];
for (let clientId = 0; clientId < this.numClients; clientId++) {
this.rilContexts[clientId] = {
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
iccInfo: null
};
this.voicemailInfos[clientId] = new VoicemailInfo();
}
this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId();
this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
this._windowsMap = [];
this._cellBroadcastListeners = [];
this._voicemailListeners = [];
this._iccListeners = [];
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
Services.prefs.addObserver(kPrefVoicemailDefaultServiceId, this, false);
}
RILContentHelper.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsICellBroadcastProvider,
Ci.nsIVoicemailProvider,
Ci.nsIIccProvider,
Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
@ -317,7 +282,6 @@ RILContentHelper.prototype = {
classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
classDescription: "RILContentHelper",
interfaces: [Ci.nsICellBroadcastProvider,
Ci.nsIVoicemailProvider,
Ci.nsIIccProvider]}),
updateDebugFlag: function() {
@ -675,52 +639,8 @@ RILContentHelper.prototype = {
},
_cellBroadcastListeners: null,
_voicemailListeners: null,
_iccListeners: null,
voicemailInfos: null,
voicemailStatuses: null,
voicemailDefaultServiceId: 0,
getVoicemailDefaultServiceId: function() {
let id = Services.prefs.getIntPref(kPrefVoicemailDefaultServiceId);
if (id >= gNumRadioInterfaces || id < 0) {
id = 0;
}
return id;
},
getVoicemailInfo: function(clientId) {
// Get voicemail infomation by IPC only on first time.
this.getVoicemailInfo = function getVoicemailInfo(clientId) {
return this.voicemailInfos[clientId];
};
for (let cId = 0; cId < gNumRadioInterfaces; cId++) {
let voicemailInfo =
cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: cId})[0];
if (voicemailInfo) {
this.updateInfo(voicemailInfo, this.voicemailInfos[cId]);
}
}
return this.voicemailInfos[clientId];
},
getVoicemailNumber: function(clientId) {
return this.getVoicemailInfo(clientId).number;
},
getVoicemailDisplayName: function(clientId) {
return this.getVoicemailInfo(clientId).displayName;
},
getVoicemailStatus: function(clientId) {
return this.voicemailStatuses[clientId];
},
registerListener: function(listenerType, clientId, listener) {
if (!this[listenerType]) {
return;
@ -754,22 +674,6 @@ RILContentHelper.prototype = {
}
},
registerVoicemailMsg: function(listener) {
if (DEBUG) debug("Registering for voicemail-related messages");
// To follow the listener registration scheme, we add a dummy clientId 0.
// All voicemail events are routed to listener for client id 0.
// See |handleVoicemailNotification|.
this.registerListener("_voicemailListeners", 0, listener);
cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg");
},
unregisterVoicemailMsg: function(listener) {
// To follow the listener unregistration scheme, we add a dummy clientId 0.
// All voicemail events are routed to listener for client id 0.
// See |handleVoicemailNotification|.
this.unregisterListener("_voicemailListeners", 0, listener);
},
registerCellBroadcastMsg: function(listener) {
if (DEBUG) debug("Registering for Cell Broadcast related messages");
// Instead of registering multiple listeners for Multi-SIM, we reuse
@ -803,8 +707,6 @@ RILContentHelper.prototype = {
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
if (data == kPrefRilDebuggingEnabled) {
this.updateDebugFlag();
} else if (data == kPrefVoicemailDefaultServiceId) {
this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId();
}
break;
@ -903,12 +805,6 @@ RILContentHelper.prototype = {
"notifyIccInfoChanged",
null);
break;
case "RIL:VoicemailNotification":
this.handleVoicemailNotification(clientId, data);
break;
case "RIL:VoicemailInfoChanged":
this.updateInfo(data, this.voicemailInfos[clientId]);
break;
case "RIL:CardLockResult": {
let requestId = data.requestId;
let requestWindow = this._windowsMap[requestId];
@ -1050,46 +946,6 @@ RILContentHelper.prototype = {
this.fireRequestSuccess(message.requestId, contact);
},
handleVoicemailNotification: function(clientId, message) {
let changed = false;
if (!this.voicemailStatuses[clientId]) {
this.voicemailStatuses[clientId] = new VoicemailStatus(clientId);
}
let voicemailStatus = this.voicemailStatuses[clientId];
if (voicemailStatus.hasMessages != message.active) {
changed = true;
voicemailStatus.hasMessages = message.active;
}
if (voicemailStatus.messageCount != message.msgCount) {
changed = true;
voicemailStatus.messageCount = message.msgCount;
} else if (message.msgCount == -1) {
// For MWI using DCS the message count is not available
changed = true;
}
if (voicemailStatus.returnNumber != message.returnNumber) {
changed = true;
voicemailStatus.returnNumber = message.returnNumber;
}
if (voicemailStatus.returnMessage != message.returnMessage) {
changed = true;
voicemailStatus.returnMessage = message.returnMessage;
}
if (changed) {
// To follow the event delivering scheme, we add a dummy clientId 0.
// All voicemail events are routed to listener for client id 0.
this._deliverEvent(0,
"_voicemailListeners",
"notifyStatusChanged",
[voicemailStatus]);
}
},
_deliverEvent: function(clientId, listenerType, name, args) {
if (!this[listenerType]) {
return;

View File

@ -127,11 +127,6 @@ const RIL_IPC_ICCMANAGER_MSG_NAMES = [
"RIL:MatchMvno"
];
const RIL_IPC_VOICEMAIL_MSG_NAMES = [
"RIL:RegisterVoicemailMsg",
"RIL:GetVoicemailInfo"
];
const RIL_IPC_CELLBROADCAST_MSG_NAMES = [
"RIL:RegisterCellBroadcastMsg"
];
@ -250,9 +245,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
ppmm.addMessageListener(msgName, this);
}
for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
@ -263,9 +255,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
ppmm.removeMessageListener(msgName, this);
}
for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
@ -384,14 +373,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
}
return null;
}
} else if (RIL_IPC_VOICEMAIL_MSG_NAMES.indexOf(msg.name) != -1) {
if (!msg.target.assertPermission("voicemail")) {
if (DEBUG) {
debug("Voicemail message " + msg.name +
" from a content process with no 'voicemail' privileges.");
}
return null;
}
} else if (RIL_IPC_CELLBROADCAST_MSG_NAMES.indexOf(msg.name) != -1) {
if (!msg.target.assertPermission("cellbroadcast")) {
if (DEBUG) {
@ -409,9 +390,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
case "RIL:RegisterIccMsg":
this._registerMessageTarget("icc", msg.target);
return null;
case "RIL:RegisterVoicemailMsg":
this._registerMessageTarget("voicemail", msg.target);
return null;
case "RIL:RegisterCellBroadcastMsg":
this._registerMessageTarget("cellbroadcast", msg.target);
return null;
@ -450,13 +428,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
});
},
sendVoicemailMessage: function(message, clientId, data) {
this._sendTargetMessage("voicemail", message, {
clientId: clientId,
data: data
});
},
sendCellBroadcastMessage: function(message, clientId, data) {
this._sendTargetMessage("cellbroadcast", message, {
clientId: clientId,
@ -1883,11 +1854,6 @@ function RadioInterface(aClientId, aWorkerMessenger) {
imsi: null
};
this.voicemailInfo = {
number: null,
displayName: null
};
this.operatorInfo = {};
let lock = gSettingsService.createLock();
@ -2067,9 +2033,6 @@ RadioInterface.prototype = {
case "RIL:MatchMvno":
this.matchMvno(msg.target, msg.json.data);
break;
case "RIL:GetVoicemailInfo":
// This message is sync.
return this.voicemailInfo;
}
return null;
},
@ -2183,8 +2146,7 @@ RadioInterface.prototype = {
this.handleIccMbdn(message);
break;
case "iccmwis":
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
this.clientId, message.mwi);
this.handleIccMwis(message.mwi);
break;
case "stkcommand":
this.handleStkProactiveCommand(message);
@ -2763,8 +2725,7 @@ RadioInterface.prototype = {
mwi.returnNumber = message.sender;
mwi.returnMessage = message.fullBody;
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
this.clientId, mwi);
this.handleIccMwis(mwi);
// Dicarded MWI comes without text body.
// Hence, we discard it here after notifying the MWI status.
@ -2968,13 +2929,16 @@ RadioInterface.prototype = {
},
handleIccMbdn: function(message) {
let voicemailInfo = this.voicemailInfo;
let service = Cc["@mozilla.org/voicemail/voicemailservice;1"]
.getService(Ci.nsIGonkVoicemailService);
service.notifyInfoChanged(this.clientId, message.number, message.alphaId);
},
voicemailInfo.number = message.number;
voicemailInfo.displayName = message.alphaId;
gMessageManager.sendVoicemailMessage("RIL:VoicemailInfoChanged",
this.clientId, voicemailInfo);
handleIccMwis: function(mwi) {
let service = Cc["@mozilla.org/voicemail/voicemailservice;1"]
.getService(Ci.nsIGonkVoicemailService);
service.notifyStatusChanged(this.clientId, mwi.active, mwi.msgCount,
mwi.returnNumber, mwi.returnMessage);
},
handleIccInfoChange: function(message) {

View File

@ -18,10 +18,8 @@ contract @mozilla.org/ril;1 {2d831c8d-6017-435b-a80c-e5d422810cea}
category profile-after-change RadioInterfaceLayer @mozilla.org/ril;1
# RILContentHelper.js
component {5467f2eb-e214-43ea-9b89-67711241ec8e} RILContentHelper.js
component {472816e1-1fd6-4405-996c-806f9ea68174} RILContentHelper.js
component {08a71987-408c-44ff-93fd-177c0a85c3dd} RILContentHelper.js
contract @mozilla.org/voicemailstatus;1 {5467f2eb-e214-43ea-9b89-67711241ec8e}
contract @mozilla.org/ril/content-helper;1 {472816e1-1fd6-4405-996c-806f9ea68174}
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

@ -23,14 +23,6 @@ interface nsIRilNetworkInterface : nsINetworkInterface
readonly attribute long mmsPort; // -1 if not set.
};
[scriptable, uuid(c0c5cb9f-6372-4b5a-b74c-baacc2da5e4f)]
interface nsIVoicemailInfo : nsISupports
{
readonly attribute DOMString number;
readonly attribute DOMString displayName;
};
[scriptable, uuid(0226a2c1-a3b9-416a-92cb-c89e4dad4be0)]
interface nsIRilContext : nsISupports
{

View File

@ -10524,6 +10524,32 @@ StkCommandParamsFactoryObject.prototype = {
return method.call(this, cmdDetails, ctlvs);
},
loadIconIfNecessary: function(cmdDetails, ctlvs, ret) {
let ctlv =
this.context.StkProactiveCmdHelper
.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return ret;
}
let iconId = ctlv.value;
ret.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
ret.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
ret.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return ret;
},
/**
* Construct a param for Refresh.
*
@ -10733,27 +10759,7 @@ StkCommandParamsFactoryObject.prototype = {
textMsg.userClear = true;
}
ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return textMsg;
}
let iconId = ctlv.value;
textMsg.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
textMsg.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
textMsg.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return textMsg;
return this.loadIconIfNecessary(cmdDetails, ctlvs, textMsg);
},
processSetUpIdleModeText: function(cmdDetails, ctlvs) {
@ -10770,27 +10776,7 @@ StkCommandParamsFactoryObject.prototype = {
}
textMsg.text = ctlv.value.textString;
ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return textMsg;
}
let iconId = ctlv.value;
textMsg.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
textMsg.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
textMsg.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return textMsg;
return this.loadIconIfNecessary(cmdDetails, ctlvs, textMsg);
},
processGetInkey: function(cmdDetails, ctlvs) {
@ -10837,27 +10823,7 @@ StkCommandParamsFactoryObject.prototype = {
input.isHelpAvailable = true;
}
ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return input;
}
let iconId = ctlv.value;
input.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
input.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
input.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return input;
return this.loadIconIfNecessary(cmdDetails, ctlvs, input);
},
processGetInput: function(cmdDetails, ctlvs) {
@ -10909,27 +10875,7 @@ StkCommandParamsFactoryObject.prototype = {
input.isHelpAvailable = true;
}
ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return input;
}
let iconId = ctlv.value;
input.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
input.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
input.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return input;
return this.loadIconIfNecessary(cmdDetails, ctlvs, input);
},
processEventNotify: function(cmdDetails, ctlvs) {
@ -10942,28 +10888,7 @@ StkCommandParamsFactoryObject.prototype = {
textMsg.text = ctlv.value.identifier;
}
ctlv = StkProactiveCmdHelper.searchForTag(
COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return textMsg;
}
let iconId = ctlv.value;
textMsg.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
textMsg.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
textMsg.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return textMsg;
return this.loadIconIfNecessary(cmdDetails, ctlvs, textMsg);
},
processSetupCall: function(cmdDetails, ctlvs) {
@ -10996,27 +10921,7 @@ StkCommandParamsFactoryObject.prototype = {
call.duration = ctlv.value;
}
ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return call;
}
let iconId = ctlv.value;
call.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
call.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
call.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return call;
return this.loadIconIfNecessary(cmdDetails, ctlvs, call);
},
processLaunchBrowser: function(cmdDetails, ctlvs) {
@ -11039,27 +10944,7 @@ StkCommandParamsFactoryObject.prototype = {
browser.mode = cmdDetails.commandQualifier & 0x03;
ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return browser;
}
let iconId = ctlv.value;
browser.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
browser.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
browser.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return browser;
return this.loadIconIfNecessary(cmdDetails, ctlvs, browser);
},
processPlayTone: function(cmdDetails, ctlvs) {
@ -11086,28 +10971,7 @@ StkCommandParamsFactoryObject.prototype = {
// vibrate is only defined in TS 102.223
playTone.isVibrate = (cmdDetails.commandQualifier & 0x01) !== 0x00;
ctlv = StkProactiveCmdHelper.searchForTag(
COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return playTone;
}
let iconId = ctlv.value;
playTone.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
playTone.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
playTone.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return playTone;
return this.loadIconIfNecessary(cmdDetails, ctlvs, playTone);
},
/**
@ -11164,27 +11028,7 @@ StkCommandParamsFactoryObject.prototype = {
bipMsg.text = ctlv.value.identifier;
}
ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
return bipMsg;
}
let iconId = ctlv.value;
bipMsg.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
let onerror = (function() {
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
let onsuccess = (function(result) {
bipMsg.icons = result[0];
this.context.RIL.sendChromeMessage(cmdDetails);
}).bind(this);
bipMsg.pending = true;
this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
return bipMsg;
return this.loadIconIfNecessary(cmdDetails, ctlvs, bipMsg);
}
};
StkCommandParamsFactoryObject.prototype[STK_CMD_REFRESH] = function STK_CMD_REFRESH(cmdDetails, ctlvs) {

View File

@ -4,7 +4,7 @@
* 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 "Voicemail.h"
#include "mozilla/dom/Voicemail.h"
#include "mozilla/dom/MozVoicemailBinding.h"
#include "mozilla/dom/MozVoicemailEvent.h"
@ -13,13 +13,17 @@
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsServiceManagerUtils.h"
#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
// Service instantiation
#include "ipc/VoicemailIPCService.h"
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
#include "nsIGonkVoicemailService.h"
#endif
#include "nsXULAppAPI.h" // For XRE_GetProcessType()
using namespace mozilla::dom;
using mozilla::ErrorResult;
class Voicemail::Listener MOZ_FINAL : public nsIVoicemailListener
{
@ -50,26 +54,67 @@ private:
NS_IMPL_ISUPPORTS(Voicemail::Listener, nsIVoicemailListener)
Voicemail::Voicemail(nsPIDOMWindow* aWindow,
nsIVoicemailProvider* aProvider)
: DOMEventTargetHelper(aWindow)
, mProvider(aProvider)
NS_IMPL_CYCLE_COLLECTION_INHERITED(Voicemail, DOMEventTargetHelper,
mStatuses)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Voicemail)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(Voicemail, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(Voicemail, DOMEventTargetHelper)
/* static */ already_AddRefed<Voicemail>
Voicemail::Create(nsPIDOMWindow* aWindow,
ErrorResult& aRv)
{
nsCOMPtr<nsIVoicemailService> service =
do_GetService(NS_VOICEMAIL_SERVICE_CONTRACTID);
if (!service) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
aWindow :
aWindow->GetCurrentInnerWindow();
nsRefPtr<Voicemail> voicemail = new Voicemail(innerWindow, service);
return voicemail.forget();
}
Voicemail::Voicemail(nsPIDOMWindow* aWindow,
nsIVoicemailService* aService)
: DOMEventTargetHelper(aWindow)
, mService(aService)
{
MOZ_ASSERT(mService);
mListener = new Listener(this);
DebugOnly<nsresult> rv = mProvider->RegisterVoicemailMsg(mListener);
DebugOnly<nsresult> rv = mService->RegisterListener(mListener);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed registering voicemail messages with provider");
"Failed registering voicemail messages with service");
uint32_t length = 0;
if (NS_SUCCEEDED(mService->GetNumItems(&length)) && length != 0) {
mStatuses.SetLength(length);
}
}
Voicemail::~Voicemail()
{
MOZ_ASSERT(mProvider && mListener);
mListener->Disconnect();
mProvider->UnregisterVoicemailMsg(mListener);
MOZ_ASSERT(!mService && !mListener);
}
NS_IMPL_ISUPPORTS_INHERITED0(Voicemail, DOMEventTargetHelper)
void
Voicemail::Shutdown()
{
mListener->Disconnect();
mService->UnregisterListener(mListener);
mListener = nullptr;
mService = nullptr;
mStatuses.Clear();
}
JSObject*
Voicemail::WrapObject(JSContext* aCx)
@ -77,133 +122,143 @@ Voicemail::WrapObject(JSContext* aCx)
return MozVoicemailBinding::Wrap(aCx, this);
}
bool
Voicemail::IsValidServiceId(uint32_t aServiceId) const
already_AddRefed<nsIVoicemailProvider>
Voicemail::GetItemByServiceId(const Optional<uint32_t>& aOptionalServiceId,
uint32_t& aActualServiceId) const
{
uint32_t numClients = mozilla::Preferences::GetUint(kPrefRilNumRadioInterfaces, 1);
return aServiceId < numClients;
}
bool
Voicemail::PassedOrDefaultServiceId(const Optional<uint32_t>& aServiceId,
uint32_t& aResult) const
{
if (aServiceId.WasPassed()) {
if (!IsValidServiceId(aServiceId.Value())) {
return false;
}
aResult = aServiceId.Value();
} else {
mProvider->GetVoicemailDefaultServiceId(&aResult);
if (!mService) {
return nullptr;
}
return true;
nsCOMPtr<nsIVoicemailProvider> provider;
if (aOptionalServiceId.WasPassed()) {
aActualServiceId = aOptionalServiceId.Value();
mService->GetItemByServiceId(aActualServiceId,
getter_AddRefs(provider));
} else {
mService->GetDefaultItem(getter_AddRefs(provider));
if (provider) {
NS_ENSURE_SUCCESS(provider->GetServiceId(&aActualServiceId), nullptr);
}
}
// For all retrieved providers, they should have service id
// < mStatuses.Length().
MOZ_ASSERT(!provider || aActualServiceId < mStatuses.Length());
return provider.forget();
}
already_AddRefed<VoicemailStatus>
Voicemail::GetOrCreateStatus(uint32_t aServiceId,
nsIVoicemailProvider* aProvider)
{
MOZ_ASSERT(aServiceId < mStatuses.Length());
MOZ_ASSERT(aProvider);
nsRefPtr<VoicemailStatus> res = mStatuses[aServiceId];
if (!res) {
mStatuses[aServiceId] = res = new VoicemailStatus(GetOwner(), aProvider);
}
return res.forget();
}
// MozVoicemail WebIDL
already_AddRefed<MozVoicemailStatus>
already_AddRefed<VoicemailStatus>
Voicemail::GetStatus(const Optional<uint32_t>& aServiceId,
ErrorResult& aRv) const
ErrorResult& aRv)
{
if (!mProvider) {
uint32_t actualServiceId = 0;
nsCOMPtr<nsIVoicemailProvider> provider =
GetItemByServiceId(aServiceId, actualServiceId);
if (!provider) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
uint32_t id = 0;
if (!PassedOrDefaultServiceId(aServiceId, id)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return nullptr;
}
JSContext *cx = nsContentUtils::GetCurrentJSContext();
JS::Rooted<JS::Value> status(cx);
nsresult rv = mProvider->GetVoicemailStatus(id, &status);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
if (!status.isObject()) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
JS::Rooted<JSObject*> statusObj(cx, &status.toObject());
nsRefPtr<MozVoicemailStatus> res = new MozVoicemailStatus(statusObj, GetParentObject());
return res.forget();
return GetOrCreateStatus(actualServiceId, provider);
}
void
Voicemail::GetNumber(const Optional<uint32_t>& aServiceId, nsString& aNumber,
Voicemail::GetNumber(const Optional<uint32_t>& aServiceId,
nsString& aNumber,
ErrorResult& aRv) const
{
aNumber.SetIsVoid(true);
if (!mProvider) {
uint32_t unused = 0;
nsCOMPtr<nsIVoicemailProvider> provider =
GetItemByServiceId(aServiceId, unused);
if (!provider) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
}
uint32_t id = 0;
if (!PassedOrDefaultServiceId(aServiceId, id)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return;
}
aRv = mProvider->GetVoicemailNumber(id, aNumber);
aRv = provider->GetNumber(aNumber);
}
void
Voicemail::GetDisplayName(const Optional<uint32_t>& aServiceId, nsString& aDisplayName,
Voicemail::GetDisplayName(const Optional<uint32_t>& aServiceId,
nsString& aDisplayName,
ErrorResult& aRv) const
{
aDisplayName.SetIsVoid(true);
if (!mProvider) {
uint32_t unused = 0;
nsCOMPtr<nsIVoicemailProvider> provider =
GetItemByServiceId(aServiceId, unused);
if (!provider) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
}
uint32_t id = 0;
if (!PassedOrDefaultServiceId(aServiceId, id)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return;
}
aRv = mProvider->GetVoicemailDisplayName(id, aDisplayName);
aRv = provider->GetDisplayName(aDisplayName);
}
// nsIVoicemailListener
NS_IMETHODIMP
Voicemail::NotifyStatusChanged(JS::HandleValue aStatus)
Voicemail::NotifyInfoChanged(nsIVoicemailProvider* aProvider)
{
// Ignored.
return NS_OK;
}
NS_IMETHODIMP
Voicemail::NotifyStatusChanged(nsIVoicemailProvider* aProvider)
{
NS_ENSURE_ARG_POINTER(aProvider);
uint32_t serviceId = 0;
if (NS_FAILED(aProvider->GetServiceId(&serviceId))) {
return NS_ERROR_UNEXPECTED;
}
MozVoicemailEventInit init;
init.mBubbles = false;
init.mCancelable = false;
if (aStatus.isObject()) {
JSContext *cx = nsContentUtils::GetCurrentJSContext();
JS::Rooted<JSObject*> statusObj(cx, &aStatus.toObject());
init.mStatus = new MozVoicemailStatus(statusObj, GetParentObject());
}
init.mStatus = GetOrCreateStatus(serviceId, aProvider);
nsRefPtr<MozVoicemailEvent> event =
MozVoicemailEvent::Constructor(this, NS_LITERAL_STRING("statuschanged"), init);
return DispatchTrustedEvent(event);
}
nsresult
NS_NewVoicemail(nsPIDOMWindow* aWindow, Voicemail** aVoicemail)
already_AddRefed<nsIVoicemailService>
NS_CreateVoicemailService()
{
nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
aWindow :
aWindow->GetCurrentInnerWindow();
nsCOMPtr<nsIVoicemailService> service;
nsCOMPtr<nsIVoicemailProvider> provider =
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
NS_ENSURE_STATE(provider);
if (XRE_GetProcessType() == GeckoProcessType_Content) {
service = new mozilla::dom::voicemail::VoicemailIPCService();
} else {
#if defined(MOZ_B2G_RIL)
#if defined(MOZ_WIDGET_GONK)
service = do_GetService(GONK_VOICEMAIL_SERVICE_CONTRACTID);
#endif // MOZ_WIDGET_GONK
#endif // MOZ_B2G_RIL
}
nsRefPtr<Voicemail> voicemail = new Voicemail(innerWindow, provider);
voicemail.forget(aVoicemail);
return NS_OK;
return service.forget();
}

View File

@ -1,5 +1,5 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* 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/. */
@ -10,7 +10,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/ErrorResult.h"
#include "nsIVoicemailProvider.h"
#include "nsIVoicemailService.h"
class JSObject;
struct JSContext;
@ -20,7 +20,7 @@ class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class MozVoicemailStatus;
class VoicemailStatus;
class Voicemail MOZ_FINAL : public DOMEventTargetHelper,
private nsIVoicemailListener
@ -28,21 +28,25 @@ class Voicemail MOZ_FINAL : public DOMEventTargetHelper,
/**
* Class Voicemail doesn't actually expose nsIVoicemailListener. Instead, it
* owns an nsIVoicemailListener derived instance mListener and passes it to
* nsIVoicemailProvider. The onreceived events are first delivered to
* nsIVoicemailService. The onreceived events are first delivered to
* mListener and then forwarded to its owner, Voicemail. See also bug 775997
* comment #51.
*/
class Listener;
virtual ~Voicemail();
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIVOICEMAILLISTENER
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Voicemail,
DOMEventTargetHelper)
Voicemail(nsPIDOMWindow* aWindow, nsIVoicemailProvider* aProvider);
static already_AddRefed<Voicemail>
Create(nsPIDOMWindow* aOwner,
ErrorResult& aRv);
void
Shutdown();
nsPIDOMWindow*
GetParentObject() const
@ -53,36 +57,54 @@ public:
virtual JSObject*
WrapObject(JSContext* aCx) MOZ_OVERRIDE;
already_AddRefed<MozVoicemailStatus>
GetStatus(const Optional<uint32_t>& aServiceId, ErrorResult& aRv) const;
already_AddRefed<VoicemailStatus>
GetStatus(const Optional<uint32_t>& aServiceId,
ErrorResult& aRv);
void
GetNumber(const Optional<uint32_t>& aServiceId, nsString& aNumber,
GetNumber(const Optional<uint32_t>& aServiceId,
nsString& aNumber,
ErrorResult& aRv) const;
void
GetDisplayName(const Optional<uint32_t>& aServiceId, nsString& aDisplayName,
GetDisplayName(const Optional<uint32_t>& aServiceId,
nsString& aDisplayName,
ErrorResult& aRv) const;
IMPL_EVENT_HANDLER(statuschanged)
private:
nsCOMPtr<nsIVoicemailProvider> mProvider;
Voicemail(nsPIDOMWindow* aWindow,
nsIVoicemailService* aService);
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~Voicemail();
private:
nsCOMPtr<nsIVoicemailService> mService;
nsRefPtr<Listener> mListener;
bool
IsValidServiceId(uint32_t aServiceId) const;
// |mStatuses| keeps all instantiated VoicemailStatus objects as well as the
// empty slots for not interested ones. The length of |mStatuses| is decided
// in the constructor and is never changed ever since.
nsAutoTArray<nsRefPtr<VoicemailStatus>, 1> mStatuses;
bool
PassedOrDefaultServiceId(const Optional<uint32_t>& aServiceId,
uint32_t& aResult) const;
// Return a nsIVoicemailProvider instance based on the requests from external
// components. Return nullptr if aOptionalServiceId contains an invalid
// service id or the default one is just not available.
already_AddRefed<nsIVoicemailProvider>
GetItemByServiceId(const Optional<uint32_t>& aOptionalServiceId,
uint32_t& aActualServiceId) const;
// Request for a valid VoicemailStatus object based on given service id and
// provider. It's the callee's responsibility to ensure the validity of the
// two parameters.
already_AddRefed<VoicemailStatus>
GetOrCreateStatus(uint32_t aServiceId,
nsIVoicemailProvider* aProvider);
};
} // namespace dom
} // namespace mozilla
nsresult
NS_NewVoicemail(nsPIDOMWindow* aWindow,
mozilla::dom::Voicemail** aVoicemail);
#endif // mozilla_dom_voicemail_voicemail_h__

View File

@ -0,0 +1,83 @@
/* -*- 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 "mozilla/dom/VoicemailStatus.h"
#include "mozilla/dom/MozVoicemailStatusBinding.h"
#include "nsIVoicemailService.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
// mProvider is owned by internal service.
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VoicemailStatus, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(VoicemailStatus)
NS_IMPL_CYCLE_COLLECTING_RELEASE(VoicemailStatus)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VoicemailStatus)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
VoicemailStatus::VoicemailStatus(nsISupports* aParent,
nsIVoicemailProvider* aProvider)
: mParent(aParent)
, mProvider(aProvider)
{
MOZ_ASSERT(mParent);
MOZ_ASSERT(mProvider);
SetIsDOMBinding();
}
JSObject*
VoicemailStatus::WrapObject(JSContext* aCx)
{
return MozVoicemailStatusBinding::Wrap(aCx, this);
}
uint32_t
VoicemailStatus::ServiceId() const
{
uint32_t result = 0;
mProvider->GetServiceId(&result);
return result;
}
bool
VoicemailStatus::HasMessages() const
{
bool result = false;
mProvider->GetHasMessages(&result);
return result;
}
int32_t
VoicemailStatus::MessageCount() const
{
int32_t result = 0;
mProvider->GetMessageCount(&result);
return result;
}
void
VoicemailStatus::GetReturnNumber(nsString& aReturnNumber) const
{
aReturnNumber.SetIsVoid(true);
mProvider->GetReturnNumber(aReturnNumber);
}
void
VoicemailStatus::GetReturnMessage(nsString& aReturnMessage) const
{
aReturnMessage.SetIsVoid(true);
mProvider->GetReturnMessage(aReturnMessage);
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,64 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* 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_voicemail_VoicemailStatus_h__
#define mozilla_dom_voicemail_VoicemailStatus_h__
#include "mozilla/Attributes.h"
#include "nsCOMPtr.h"
#include "nsIVoicemailService.h" // For nsIVoicemailProvider.
#include "nsString.h"
#include "nsWrapperCache.h"
namespace mozilla {
namespace dom {
class VoicemailStatus MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(VoicemailStatus)
VoicemailStatus(nsISupports* aParent,
nsIVoicemailProvider* aProvider);
nsISupports*
GetParentObject() const { return mParent; }
virtual JSObject*
WrapObject(JSContext* aCx) MOZ_OVERRIDE;
// WebIDL interface
uint32_t
ServiceId() const;
bool
HasMessages() const;
int32_t
MessageCount() const;
void
GetReturnNumber(nsString& aReturnNumber) const;
void
GetReturnMessage(nsString& aReturnMessage) const;
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~VoicemailStatus() {}
private:
nsCOMPtr<nsISupports> mParent;
nsCOMPtr<nsIVoicemailProvider> mProvider;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_voicemail_VoicemailStatus_h__

View File

@ -0,0 +1,260 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
let obj = {};
Cu.import("resource://gre/modules/ril_consts.js", obj);
return obj;
});
const GONK_VOICEMAIL_SERVICE_CONTRACTID =
"@mozilla.org/voicemail/gonkvoicemailservice;1";
const GONK_VOICEMAIL_SERVICE_CID =
Components.ID("{c332f318-1cce-4f02-b676-bb5031d10736}");
const NS_MOBILE_CONNECTION_SERVICE_CONTRACTID =
"@mozilla.org/mobileconnection/mobileconnectionservice;1";
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
const kPrefDefaultServiceId = "dom.voicemail.defaultServiceId";
let DEBUG;
function debug(s) {
dump("VoicemailService: " + s);
}
function VoicemailProvider(aServiceId) {
this.serviceId = aServiceId;
}
VoicemailProvider.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIVoicemailProvider]),
// nsIVoicemail interface
serviceId: 0,
number: null,
displayName: null,
hasMessages: false,
messageCount: 0,
returnNumber: null,
returnMessage: null,
};
function VoicemailService() {
// Initialize |this._providers|.
let mcService = Cc[NS_MOBILE_CONNECTION_SERVICE_CONTRACTID]
.getService(Ci.nsIMobileConnectionService);
let numItems = mcService.numItems;
this._providers = [];
for (let i = 0; i < numItems; i++) {
this._providers.push(new VoicemailProvider(i));
}
this._listeners = [];
// Must be initialized after |this._providers|.
this._defaultServiceId = this._getDefaultServiceId();
this._updateDebugFlag();
Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
Services.prefs.addObserver(kPrefDefaultServiceId, this, false);
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
}
VoicemailService.prototype = {
classID: GONK_VOICEMAIL_SERVICE_CID,
classInfo: XPCOMUtils.generateCI({
classID: GONK_VOICEMAIL_SERVICE_CID,
contractID: GONK_VOICEMAIL_SERVICE_CONTRACTID,
classDescription: "VoicemailService",
interfaces: [
Ci.nsIVoicemailService,
Ci.nsIGonkVoicemailService
],
flags: Ci.nsIClassInfo.SINGLETON
}),
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIVoicemailService,
Ci.nsIGonkVoicemailService,
Ci.nsIObserver
]),
_defaultServiceId: null,
_providers: null,
_updateDebugFlag: function() {
try {
DEBUG = RIL.DEBUG_RIL ||
Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
} catch (e) {}
},
_getDefaultServiceId: function() {
let id = Services.prefs.getIntPref(kPrefDefaultServiceId);
if (id >= this.numItems || id < 0) {
id = 0;
}
return id;
},
_listeners: null,
_notifyListeners: function(aMethodName, aItem) {
let listeners = this._listeners.slice();
for (let listener of listeners) {
try {
listener[aMethodName].call(listener, aItem);
} catch (e) {
if (DEBUG) {
debug("listener for " + aMethodName + " threw an exception: " + e);
}
}
}
},
/**
* nsIVoicemailService interface
*/
get numItems() {
return this._providers.length;
},
getItemByServiceId: function(aServiceId) {
let provider = this._providers[aServiceId];
if (!provider) {
throw Cr.NS_ERROR_INVALID_ARG;
}
return provider;
},
getDefaultItem: function() {
return this.getItemByServiceId(this._defaultServiceId);
},
registerListener: function(aListener) {
if (this._listeners.indexOf(aListener) >= 0) {
throw Cr.NS_ERROR_UNEXPECTED;
}
this._listeners.push(aListener);
},
unregisterListener: function(aListener) {
let index = this._listeners.indexOf(aListener);
if (index < 0) {
return Cr.NS_ERROR_FAILURE;
}
this._listeners.splice(index, 1);
},
/**
* nsIGonkVoicemailService interface
*/
notifyStatusChanged: function(aServiceId, aHasMessages, aMessageCount,
aReturnNumber, aReturnMessage) {
if (DEBUG) {
debug("notifyStatusChanged: " +
JSON.stringify(Array.prototype.slice.call(arguments)));
}
let provider = this.getItemByServiceId(aServiceId);
let changed = false;
if (provider.hasMessages != aHasMessages) {
provider.hasMessages = aHasMessages;
changed = true;
}
if (provider.messageCount != aMessageCount) {
provider.messageCount = aMessageCount;
changed = true;
} else if (aMessageCount == -1) {
// For MWI using DCS the message count is not available
changed = true;
}
if (provider.returnNumber != aReturnNumber) {
provider.returnNumber = aReturnNumber;
changed = true;
}
if (provider.returnMessage != aReturnMessage) {
provider.returnMessage = aReturnMessage;
changed = true;
}
if (changed) {
this._notifyListeners("notifyStatusChanged", provider);
}
},
notifyInfoChanged: function(aServiceId, aNumber, aDisplayName) {
if (DEBUG) {
debug("notifyInfoChanged: " +
JSON.stringify(Array.prototype.slice.call(arguments)));
}
let provider = this.getItemByServiceId(aServiceId);
let changed = false;
if (provider.number != aNumber) {
provider.number = aNumber;
changed = true;
}
if (provider.displayName != aDisplayName) {
provider.displayName = aDisplayName;
changed = true;
}
if (changed) {
this._notifyListeners("notifyInfoChanged", provider);
}
},
/**
* nsIObserver interface.
*/
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
if (aData === kPrefRilDebuggingEnabled) {
this._updateDebugFlag();
} else if (aData === kPrefDefaultServiceId) {
this._defaultServiceId = this._getDefaultServiceId();
}
break;
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
Services.prefs.removeObserver(kPrefRilDebuggingEnabled, this);
Services.prefs.removeObserver(kPrefDefaultServiceId, this);
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
// Remove all listeners.
this._listeners = [];
break;
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([VoicemailService]);

View File

@ -0,0 +1,7 @@
# 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/.
component {c332f318-1cce-4f02-b676-bb5031d10736} VoicemailService.js
contract @mozilla.org/voicemail/gonkvoicemailservice;1 {c332f318-1cce-4f02-b676-bb5031d10736}

View File

@ -0,0 +1,30 @@
/* 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 "nsIVoicemailService.idl"
%{C++
#define GONK_VOICEMAIL_SERVICE_CONTRACTID \
"@mozilla.org/voicemail/gonkvoicemailservice;1"
%}
[scriptable, uuid(d21dbc55-f540-417d-aa3e-9e890764e957)]
interface nsIGonkVoicemailService : nsIVoicemailService
{
/**
* Called when a voicemail notification has been received by the network.
*/
void notifyStatusChanged(in unsigned long serviceId,
in bool hasMessages,
in long messageCount,
in DOMString returnNumber,
in DOMString returnMessage);
/**
* Called when other voicemail attributes changed.
*/
void notifyInfoChanged(in unsigned long serviceId,
in DOMString number,
in DOMString displayName);
};

View File

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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 protocol PContent;
namespace mozilla {
namespace dom {
namespace voicemail {
sync protocol PVoicemail
{
manager PContent;
child:
NotifyInfoChanged(uint32_t aServiceId,
nsString aNumber,
nsString aDisplayName);
NotifyStatusChanged(uint32_t aServiceId,
bool aHasMessages,
int32_t aMessageCount,
nsString aNumber,
nsString aDisplayName);
parent:
/**
* Send when child no longer needs to use PVoicemail.
*/
__delete__();
sync GetAttributes(uint32_t aServiceId)
returns (nsString aNumber,
nsString aDisplayName,
bool aHasMessages,
int32_t aMessageCount,
nsString aReturnNumber,
nsString aReturnMessage);
};
} // namespace voicemail
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,261 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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 "mozilla/dom/voicemail/VoicemailIPCService.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Preferences.h"
#include "nsIMobileConnectionService.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
namespace dom {
namespace voicemail {
class VoicemailIPCProvider MOZ_FINAL : public nsIVoicemailProvider
{
friend class VoicemailIPCService;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIVOICEMAILPROVIDER
VoicemailIPCProvider(uint32_t aServiceId);
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~VoicemailIPCProvider() {}
private:
uint32_t mServiceId;
nsString mNumber;
nsString mDisplayName;
bool mHasMessages;
int32_t mMessageCount;
nsString mReturnNumber;
nsString mReturnMessage;
};
NS_IMPL_ISUPPORTS(VoicemailIPCProvider, nsIVoicemailProvider)
VoicemailIPCProvider::VoicemailIPCProvider(uint32_t aServiceId)
: mServiceId(aServiceId)
, mHasMessages(false)
, mMessageCount(0)
{
}
// nsIVoicemailProvider
NS_IMETHODIMP
VoicemailIPCProvider::GetServiceId(uint32_t* aServiceId)
{
NS_ENSURE_ARG_POINTER(aServiceId);
*aServiceId = mServiceId;
return NS_OK;
}
NS_IMETHODIMP
VoicemailIPCProvider::GetNumber(nsAString& aNumber)
{
aNumber = mNumber;
return NS_OK;
}
NS_IMETHODIMP
VoicemailIPCProvider::GetDisplayName(nsAString& aDisplayName)
{
aDisplayName = mDisplayName;
return NS_OK;
}
NS_IMETHODIMP
VoicemailIPCProvider::GetHasMessages(bool* aHasMessages)
{
NS_ENSURE_ARG_POINTER(aHasMessages);
*aHasMessages = mHasMessages;
return NS_OK;
}
NS_IMETHODIMP
VoicemailIPCProvider::GetMessageCount(int32_t* aMessageCount)
{
NS_ENSURE_ARG_POINTER(aMessageCount);
*aMessageCount = mMessageCount;
return NS_OK;
}
NS_IMETHODIMP
VoicemailIPCProvider::GetReturnNumber(nsAString& aReturnNumber)
{
aReturnNumber = mReturnNumber;
return NS_OK;
}
NS_IMETHODIMP
VoicemailIPCProvider::GetReturnMessage(nsAString& aReturnMessage)
{
aReturnMessage = mReturnMessage;
return NS_OK;
}
NS_IMPL_ISUPPORTS(VoicemailIPCService, nsIVoicemailService)
VoicemailIPCService::VoicemailIPCService()
: mActorDestroyed(false)
{
ContentChild::GetSingleton()->SendPVoicemailConstructor(this);
nsCOMPtr<nsIMobileConnectionService> mcService =
do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
if (mcService) {
uint32_t length = 0;
if (NS_SUCCEEDED(mcService->GetNumItems(&length))) {
mProviders.SetLength(length);
}
}
}
VoicemailIPCService::~VoicemailIPCService()
{
if (!mActorDestroyed) {
Send__delete__(this);
}
}
// PVoicemailChild
bool
VoicemailIPCService::RecvNotifyInfoChanged(const uint32_t& aServiceId,
const nsString& aNumber,
const nsString& aDisplayName)
{
nsCOMPtr<nsIVoicemailProvider> provider;
NS_ENSURE_SUCCESS(GetItemByServiceId(aServiceId, getter_AddRefs(provider)), false);
VoicemailIPCProvider* pProvider =
static_cast<VoicemailIPCProvider*>(provider.get());
pProvider->mNumber = aNumber;
pProvider->mDisplayName = aDisplayName;
// Listeners may unregister itself upon a info changed event, so we make a
// copy first.
nsTArray<nsCOMPtr<nsIVoicemailListener>> copy(mListeners);
for (uint32_t i = 0; i < copy.Length(); i++) {
copy[i]->NotifyInfoChanged(provider);
}
return true;
}
bool
VoicemailIPCService::RecvNotifyStatusChanged(const uint32_t& aServiceId,
const bool& aHasMessages,
const int32_t& aMessageCount,
const nsString& aReturnNumber,
const nsString& aReturnMessage)
{
nsCOMPtr<nsIVoicemailProvider> provider;
NS_ENSURE_SUCCESS(GetItemByServiceId(aServiceId, getter_AddRefs(provider)), false);
VoicemailIPCProvider* pProvider =
static_cast<VoicemailIPCProvider*>(provider.get());
pProvider->mHasMessages = aHasMessages;
pProvider->mMessageCount = aMessageCount;
pProvider->mReturnNumber = aReturnNumber;
pProvider->mReturnMessage = aReturnMessage;
// Listeners may unregister itself upon a info changed event, so we make a
// copy first.
nsTArray<nsCOMPtr<nsIVoicemailListener>> copy(mListeners);
for (uint32_t i = 0; i < copy.Length(); i++) {
copy[i]->NotifyStatusChanged(provider);
}
return true;
}
void
VoicemailIPCService::ActorDestroy(ActorDestroyReason aWhy)
{
mActorDestroyed = true;
}
// nsIVoicemailService
NS_IMETHODIMP
VoicemailIPCService::GetNumItems(uint32_t* aNumItems)
{
NS_ENSURE_ARG_POINTER(aNumItems);
*aNumItems = mProviders.Length();
return NS_OK;
}
NS_IMETHODIMP
VoicemailIPCService::GetItemByServiceId(uint32_t aServiceId,
nsIVoicemailProvider** aProvider)
{
NS_ENSURE_ARG(aServiceId < mProviders.Length());
NS_ENSURE_ARG_POINTER(aProvider);
if (!mProviders[aServiceId]) {
nsRefPtr<VoicemailIPCProvider> provider =
new VoicemailIPCProvider(aServiceId);
if (!SendGetAttributes(aServiceId,
&(provider->mNumber),
&(provider->mDisplayName),
&(provider->mHasMessages),
&(provider->mMessageCount),
&(provider->mReturnNumber),
&(provider->mReturnMessage))) {
return NS_ERROR_FAILURE;
}
mProviders[aServiceId] = provider;
}
nsRefPtr<nsIVoicemailProvider> provider(mProviders[aServiceId]);
provider.forget(aProvider);
return NS_OK;
}
NS_IMETHODIMP
VoicemailIPCService::GetDefaultItem(nsIVoicemailProvider** aProvider)
{
NS_ENSURE_ARG_POINTER(aProvider);
int defaultServiceId =
Preferences::GetInt("dom.voicemail.defaultServiceId", 0);
return GetItemByServiceId(defaultServiceId, aProvider);
}
NS_IMETHODIMP
VoicemailIPCService::RegisterListener(nsIVoicemailListener* aListener)
{
NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_UNEXPECTED);
NS_ENSURE_TRUE(!mListeners.Contains(aListener), NS_ERROR_UNEXPECTED);
mListeners.AppendElement(aListener);
return NS_OK;
}
NS_IMETHODIMP
VoicemailIPCService::UnregisterListener(nsIVoicemailListener* aListener)
{
NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_UNEXPECTED);
return mListeners.RemoveElement(aListener) ? NS_OK : NS_ERROR_UNEXPECTED;
}
} // namespace voicemail
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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_voicemail_VoicemailIPCService_h
#define mozilla_dom_voicemail_VoicemailIPCService_h
#include "mozilla/Attributes.h"
#include "mozilla/dom/voicemail/PVoicemailChild.h"
#include "nsAutoPtr.h"
#include "nsIVoicemailService.h"
namespace mozilla {
namespace dom {
namespace voicemail {
class VoicemailIPCService MOZ_FINAL : public PVoicemailChild
, public nsIVoicemailService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIVOICEMAILSERVICE
VoicemailIPCService();
bool
RecvNotifyInfoChanged(const uint32_t& aServiceId,
const nsString& aNumber,
const nsString& aDisplayName) MOZ_OVERRIDE;
bool
RecvNotifyStatusChanged(const uint32_t& aServiceId,
const bool& aHasMessages,
const int32_t& aMessageCount,
const nsString& aNumber,
const nsString& aDisplayName) MOZ_OVERRIDE;
void
ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~VoicemailIPCService();
private:
bool mActorDestroyed;
nsTArray<nsCOMPtr<nsIVoicemailListener>> mListeners;
nsTArray<nsCOMPtr<nsIVoicemailProvider>> mProviders;
};
} // namespace voicemail
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_voicemail_VoicemailIPCService_h

View File

@ -0,0 +1,92 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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 "mozilla/dom/voicemail/VoicemailParent.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
namespace dom {
namespace voicemail {
NS_IMPL_ISUPPORTS(VoicemailParent,
nsIVoicemailListener)
bool
VoicemailParent::Init()
{
mService = do_GetService(NS_VOICEMAIL_SERVICE_CONTRACTID);
return mService && NS_SUCCEEDED(mService->RegisterListener(this));
}
bool
VoicemailParent::RecvGetAttributes(const uint32_t& aServiceId,
nsString* aNumber,
nsString* aDisplayName,
bool* aHasMessages,
int32_t* aMessageCount,
nsString* aReturnNumber,
nsString* aReturnMessage)
{
nsCOMPtr<nsIVoicemailProvider> provider;
NS_ENSURE_SUCCESS(mService->GetItemByServiceId(aServiceId,
getter_AddRefs(provider)), false);
provider->GetNumber(*aNumber);
provider->GetDisplayName(*aDisplayName);
provider->GetHasMessages(aHasMessages);
provider->GetMessageCount(aMessageCount);
provider->GetReturnNumber(*aReturnNumber);
provider->GetReturnMessage(*aReturnMessage);
return true;
}
void
VoicemailParent::ActorDestroy(ActorDestroyReason aWhy)
{
mService->UnregisterListener(this);
mService = nullptr;
}
// nsIVoicemailListener
NS_IMETHODIMP
VoicemailParent::NotifyInfoChanged(nsIVoicemailProvider* aProvider)
{
uint32_t serviceId = 0;
nsString number, displayName;
aProvider->GetServiceId(&serviceId);
aProvider->GetNumber(number);
aProvider->GetDisplayName(displayName);
return SendNotifyInfoChanged(serviceId, number, displayName)
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
VoicemailParent::NotifyStatusChanged(nsIVoicemailProvider* aProvider)
{
uint32_t serviceId = 0;
bool hasMessages = false;
int32_t messageCount = 0;
nsString returnNumber, returnMessage;
aProvider->GetServiceId(&serviceId);
aProvider->GetHasMessages(&hasMessages);
aProvider->GetMessageCount(&messageCount);
aProvider->GetReturnNumber(returnNumber);
aProvider->GetReturnMessage(returnMessage);
return SendNotifyStatusChanged(serviceId, hasMessages, messageCount,
returnNumber, returnMessage)
? NS_OK : NS_ERROR_FAILURE;
}
} // namespace voicemail
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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_voicemail_VoicemailParent_h
#define mozilla_dom_voicemail_VoicemailParent_h
#include "mozilla/Attributes.h"
#include "mozilla/dom/voicemail/PVoicemailParent.h"
#include "mozilla/dom/voicemail/VoicemailParent.h"
#include "nsAutoPtr.h"
#include "nsIVoicemailService.h"
#include "nsString.h"
namespace mozilla {
namespace dom {
namespace voicemail {
class VoicemailParent MOZ_FINAL : public PVoicemailParent
, public nsIVoicemailListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIVOICEMAILLISTENER
VoicemailParent() { MOZ_COUNT_CTOR(VoicemailParent); }
bool
Init();
bool
RecvGetAttributes(const uint32_t& aServiceId,
nsString* aNumber,
nsString* aDisplayName,
bool* aHasMessages,
int32_t* aMessageCount,
nsString* aReturnNumber,
nsString* aReturnMessage) MOZ_OVERRIDE;
void
ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~VoicemailParent() { MOZ_COUNT_DTOR(VoicemailParent); }
private:
nsCOMPtr<nsIVoicemailService> mService;
};
} // namespace voicemail
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_voicemail_VoicemailParent_h

View File

@ -5,23 +5,51 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsIVoicemailProvider.idl',
'nsIVoicemailService.idl',
]
XPIDL_MODULE = 'dom_voicemail'
EXPORTS.mozilla.dom += [
'Voicemail.h',
'VoicemailStatus.h',
]
EXPORTS.mozilla.dom.voicemail += [
'ipc/VoicemailIPCService.h',
'ipc/VoicemailParent.h',
]
IPDL_SOURCES += [
'ipc/PVoicemail.ipdl',
]
SOURCES += [
'ipc/VoicemailIPCService.cpp',
'ipc/VoicemailParent.cpp',
'Voicemail.cpp',
]
UNIFIED_SOURCES += [
'VoicemailStatus.cpp',
]
if CONFIG['MOZ_B2G_RIL']:
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
XPIDL_SOURCES += [
'gonk/nsIGonkVoicemailService.idl',
]
EXTRA_COMPONENTS += [
'gonk/VoicemailService.js',
'gonk/VoicemailService.manifest',
]
FAIL_ON_WARNINGS = True
LOCAL_INCLUDES += [
'../base',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View File

@ -1,39 +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, uuid(214b0963-da48-4859-a56c-f065a90e0403)]
interface nsIVoicemailListener : nsISupports
{
/**
* Called when a voicemail notification has been received by the network.
*
* @param status
* The new voicemail status
*/
void notifyStatusChanged(in jsval status);
};
/**
* XPCOM component (in the content process) that provides the voicemail
* information.
*/
[scriptable, uuid(1bbfff90-88f7-4d73-896e-9620a0000ab0)]
interface nsIVoicemailProvider : nsISupports
{
readonly attribute unsigned long voicemailDefaultServiceId;
/**
* Called when a content process registers receiving unsolicited messages from
* RadioInterfaceLayer in the chrome process. Only a content process that has
* the 'voicemail' permission is allowed to register.
*/
void registerVoicemailMsg(in nsIVoicemailListener listener);
void unregisterVoicemailMsg(in nsIVoicemailListener listener);
jsval getVoicemailStatus(in unsigned long clientId);
DOMString getVoicemailNumber(in unsigned long clientId);
DOMString getVoicemailDisplayName(in unsigned long clientId);
};

View File

@ -0,0 +1,137 @@
/* 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 nsIVoicemailProvider;
[scriptable, uuid(6a8b0133-960d-409d-88cd-583239e45f9f)]
interface nsIVoicemailListener : nsISupports
{
/**
* Called when a voicemail status (hasMessages, messageCount, returnNumber,
* returnMessage) changed.
*/
void notifyStatusChanged(in nsIVoicemailProvider provider);
/**
* Called when a voicemail info (number, displayName) changed.
*/
void notifyInfoChanged(in nsIVoicemailProvider provider);
};
%{C++
#define NS_VOICEMAIL_SERVICE_CID \
{ 0xcdd8fd72, 0x7d55, 0x496b, \
{ 0xab, 0x1d, 0x74, 0x9f, 0xbc, 0x44, 0x56, 0x32 } }
#define NS_VOICEMAIL_SERVICE_CONTRACTID \
"@mozilla.org/voicemail/voicemailservice;1"
%}
/**
* XPCOM component (in the content process) that provides the voicemail
* information.
*/
[scriptable, uuid(8ffd16c7-a614-4c4a-81f0-2a95e807152d)]
interface nsIVoicemailService : nsISupports
{
readonly attribute unsigned long numItems;
nsIVoicemailProvider getItemByServiceId(in unsigned long serviceId);
nsIVoicemailProvider getDefaultItem();
/**
* Called when any one who is interested in receiving unsolicited messages.
*/
void registerListener(in nsIVoicemailListener listener);
void unregisterListener(in nsIVoicemailListener listener);
};
%{C++
template<typename T> struct already_AddRefed;
already_AddRefed<nsIVoicemailService>
NS_CreateVoicemailService();
%}
[scriptable, uuid(a0bc19a2-3216-4f3f-89d3-8976a48cb829)]
interface nsIVoicemailProvider : nsISupports
{
readonly attribute unsigned long serviceId;
/**
* Voicemail center number. When changed, |notifyInfoChanged| of registered
* nsIVoicemailListener instances are called.
*
* Default: null
*
* @see 3GPP TS 31.102 subclause 4.2.63 "EFmwis (Message Waiting Indication Status)"
* @see 3GPP TS 51.011 subclause 10.3.45 "EFmwis (Message Waiting Indication Status)"
*/
readonly attribute DOMString number;
/**
* Voicemail center display name. When changed, |notifyInfoChanged| of
* registered nsIVoicemailListener instances are called.
*
* Default: null
*
* @see 3GPP TS 31.102 subclause 4.2.63 "EFmwis (Message Waiting Indication Status)"
* @see 3GPP TS 51.011 subclause 10.3.45 "EFmwis (Message Waiting Indication Status)"
*/
readonly attribute DOMString displayName;
/**
* Whether or not there are messages waiting in the voicemail box. When
* changed, |notifyStatusChanged| of registered nsIVoicemailListener instances
* are called.
*
* Default: false
*
* @see 3GPP TS 23.038 chapter 4 "SMS Data Coding Scheme"
* @see 3GPP TS 23.040 subclause 9.2.3.24.2 "Special SMS Message Indication"
*/
readonly attribute boolean hasMessages;
/**
* When #hasMessages is true, #messageCount should be a positive number for
* the messages waiting, or -1 if the exact number is not available. When
* changed, |notifyStatusChanged| of registered nsIVoicemailListener instances
* are called.
*
* Default: 0
*
* @see 3GPP TS 23.040 subclause 9.2.3.24.2 "Special SMS Message Indication"
*/
readonly attribute long messageCount;
/**
* A Return Call Message indicates to the MS to inform the user that a call
* (e.g. a telephone call) can be established to the address specified within
* the #returnNumber. The #returnMessage (if present) gives displayable
* information (e.g. the number of waiting voice messages).
*
* When #hasMessages is true this may contain a non-null string as the phone
* number of a Return Call Message. When changed, |notifyStatusChanged| of
* registered nsIVoicemailListener instances are called.
*
* Default: null
*
* @see 3GPP TS 23.040 subclause 9.2.3.9 "TPProtocolIdentifier (TPPID)"
*/
readonly attribute DOMString returnNumber;
/**
* When #hasMessages is true this may contain a non-null string as the
* notification message of a Return Call Message. When changed,
* |notifyStatusChanged| of registered nsIVoicemailListener instances are
* called.
*
* Default: null
*
* @see 3GPP TS 23.040 subclause 9.2.3.9 "TPProtocolIdentifier (TPPID)"
*/
readonly attribute DOMString returnMessage;
};

View File

@ -0,0 +1,415 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
let RIL = {};
Cu.import("resource://gre/modules/ril_consts.js", RIL);
let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
const MWI_PDU_PREFIX = "0000";
const MWI_PDU_UDH_PREFIX = "0040";
const MWI_PID_DEFAULT = "00";
const MWI_DCS_DISCARD_INACTIVE = "C0";
const MWI_DCS_DISCARD_ACTIVE = "C8";
const MWI_TIMESTAMP = "00000000000000";
// Only bring in what we need from ril_worker/RadioInterfaceLayer here. Reusing
// that code turns out to be a nightmare, so there is some code duplication.
let PDUBuilder = {
toHexString: function(n, length) {
let str = n.toString(16);
if (str.length < length) {
for (let i = 0; i < length - str.length; i++) {
str = "0" + str;
}
}
return str.toUpperCase();
},
writeUint16: function(value) {
this.buf += (value & 0xff).toString(16).toUpperCase();
this.buf += ((value >> 8) & 0xff).toString(16).toUpperCase();
},
writeHexOctet: function(octet) {
this.buf += this.toHexString(octet, 2);
},
writeSwappedNibbleBCD: function(data) {
data = data.toString();
let zeroCharCode = '0'.charCodeAt(0);
for (let i = 0; i < data.length; i += 2) {
let low = data.charCodeAt(i) - zeroCharCode;
let high;
if (i + 1 < data.length) {
high = data.charCodeAt(i + 1) - zeroCharCode;
} else {
high = 0xF;
}
this.writeHexOctet((high << 4) | low);
}
},
writeStringAsSeptets: function(message, paddingBits, langIndex,
langShiftIndex) {
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
let dataBits = paddingBits;
let data = 0;
for (let i = 0; i < message.length; i++) {
let septet = langTable.indexOf(message[i]);
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
continue;
}
if (septet >= 0) {
data |= septet << dataBits;
dataBits += 7;
} else {
septet = langShiftTable.indexOf(message[i]);
if (septet == -1) {
throw new Error(message[i] + " not in 7 bit alphabet "
+ langIndex + ":" + langShiftIndex + "!");
}
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
continue;
}
data |= RIL.PDU_NL_EXTENDED_ESCAPE << dataBits;
dataBits += 7;
data |= septet << dataBits;
dataBits += 7;
}
for (; dataBits >= 8; dataBits -= 8) {
this.writeHexOctet(data & 0xFF);
data >>>= 8;
}
}
if (dataBits != 0) {
this.writeHexOctet(data & 0xFF);
}
},
buildAddress: function(address) {
let addressFormat = RIL.PDU_TOA_ISDN; // 81
if (address[0] == '+') {
addressFormat = RIL.PDU_TOA_INTERNATIONAL | RIL.PDU_TOA_ISDN; // 91
address = address.substring(1);
}
this.buf = "";
this.writeHexOctet(address.length);
this.writeHexOctet(addressFormat);
this.writeSwappedNibbleBCD(address);
return this.buf;
},
// assumes 7 bit encoding
buildUserData: function(options) {
let headerLength = 0;
this.buf = "";
if (options.headers) {
for each (let header in options.headers) {
headerLength += 2; // id + length octets
if (header.octets) {
headerLength += header.octets.length;
}
};
}
let encodedBodyLength = options.body.length;
let headerOctets = (headerLength ? headerLength + 1 : 0);
let paddingBits;
let userDataLengthInSeptets;
let headerSeptets = Math.ceil(headerOctets * 8 / 7);
userDataLengthInSeptets = headerSeptets + encodedBodyLength;
paddingBits = headerSeptets * 7 - headerOctets * 8;
this.writeHexOctet(userDataLengthInSeptets);
if (options.headers) {
this.writeHexOctet(headerLength);
for each (let header in options.headers) {
this.writeHexOctet(header.id);
this.writeHexOctet(header.length);
if (header.octets) {
for each (let octet in header.octets) {
this.writeHexOctet(octet);
}
}
}
}
this.writeStringAsSeptets(options.body, paddingBits,
RIL.PDU_NL_IDENTIFIER_DEFAULT,
RIL.PDU_NL_IDENTIFIER_DEFAULT);
return this.buf;
},
buildLevel2DiscardMwi: function(aActive, aSender, aBody) {
return MWI_PDU_PREFIX +
this.buildAddress(aSender) +
MWI_PID_DEFAULT +
(aActive ? MWI_DCS_DISCARD_ACTIVE : MWI_DCS_DISCARD_INACTIVE) +
MWI_TIMESTAMP +
this.buildUserData({ body: aBody });
},
buildLevel3DiscardMwi: function(aMessageCount, aSender, aBody) {
let options = {
headers: [{
id: RIL.PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION,
length: 2,
octets: [
RIL.PDU_MWI_STORE_TYPE_DISCARD,
aMessageCount || 0
]
}],
body: aBody
};
return MWI_PDU_UDH_PREFIX +
this.buildAddress(aSender) +
MWI_PID_DEFAULT +
MWI_DCS_DISCARD_ACTIVE +
MWI_TIMESTAMP +
this.buildUserData(options);
}
};
let pendingEmulatorCmdCount = 0;
/**
* Send emulator command with safe guard.
*
* We should only call |finish()| after all emulator command transactions
* end, so here comes with the pending counter. Resolve when the emulator
* gives positive response, and reject otherwise.
*
* Fulfill params:
* result -- an array of emulator response lines.
*
* Reject params:
* result -- an array of emulator response lines.
*
* @return A deferred promise.
*/
function runEmulatorCmdSafe(aCommand) {
let deferred = Promise.defer();
++pendingEmulatorCmdCount;
runEmulatorCmd(aCommand, function(aResult) {
--pendingEmulatorCmdCount;
ok(true, "Emulator response: " + JSON.stringify(aResult));
if (Array.isArray(aResult) && aResult[0] === "OK") {
deferred.resolve(aResult);
} else {
deferred.reject(aResult);
}
});
return deferred.promise;
}
/**
* Promise wrapper for |SpecialPowers.pushPermissions|.
*
* Fulfill params: a MozVoicemail object.
* Reject params: (none)
*
* @param aPermissions
* A permission operation description array. See
* |SpecialPowers.pushPermissions| for more details.
*
* @return A deferred promise.
*/
function pushPermissions(aPermissions) {
let deferred = Promise.defer();
SpecialPowers.pushPermissions(aPermissions, function() {
ok(true, "permissions pushed: " + JSON.stringify(aPermissions));
deferred.resolve();
});
return deferred.promise;
}
let voicemail;
/**
* Add required permissions and test if |navigator.mozVoicemail| exists.
*
* Fulfill params: a MozVoicemail object.
* Reject params: (none)
*
* @return A deferred promise.
*/
function ensureVoicemail() {
let permissions = [{
"type": "voicemail",
"allow": 1,
"context": document,
}];
return pushPermissions(permissions)
.then(function() {
voicemail = window.navigator.mozVoicemail;
if (voicemail == null) {
throw "navigator.mozVoicemail is undefined.";
}
if (!(voicemail instanceof MozVoicemail)) {
throw "navigator.mozVoicemail is instance of " + voicemail.constructor;
}
return voicemail;
});
}
/**
* Wait for one named voicemail event.
*
* Resolve if that named event occurs. Never reject.
*
* Fulfill params: the DOMEvent passed.
*
* @param aEventName
* A string event name.
* @param aMatchFunc [optional]
* An additional callback function to match the interested event
* before removing the listener and going to resolve the promise.
*
* @return A deferred promise.
*/
function waitForManagerEvent(aEventName, aMatchFunc) {
let deferred = Promise.defer();
voicemail.addEventListener(aEventName, function onevent(aEvent) {
if (aMatchFunc && !aMatchFunc(aEvent)) {
ok(true, "MozVoicemail event '" + aEventName + "' got" +
" but is not interested.");
return;
}
ok(true, "MozVoicemail event '" + aEventName + "' got.");
voicemail.removeEventListener(aEventName, onevent);
deferred.resolve(aEvent);
});
return deferred.promise;
}
/**
* Send raw voicemail indicator PDU. Resolve if the indicator PDU was sent with
* success.
*
* Fulfill params: (none)
* Reject params: (none)
*
* @return A deferred promise.
*/
function sendIndicatorPDU(aPDU) {
return runEmulatorCmdSafe("sms pdu " + aPDU);
}
/**
* Send raw voicemail indicator PDU and wait for "statuschanged" event. Resolve
* if the indicator was sent and a "statuschanged" event was dispatched to
* |navigator.mozVoicemail|.
*
* Fulfill params: (none)
* Reject params: (none)
*
* @return A deferred promise.
*/
function sendIndicatorPDUAndWait(aPDU) {
let promises = [];
promises.push(waitForManagerEvent("statuschanged"));
promises.push(sendIndicatorPDU(aPDU));
return Promise.all(promises);
}
/**
* Check equalities of all attributes of two VoicemailStatus instances.
*/
function compareVoicemailStatus(aStatus1, aStatus2) {
is(aStatus1.serviceId, aStatus2.serviceId, "VoicemailStatus::serviceId");
is(aStatus1.hasMessages, aStatus2.hasMessages, "VoicemailStatus::hasMessages");
is(aStatus1.messageCount, aStatus2.messageCount, "VoicemailStatus::messageCount");
is(aStatus1.returnNumber, aStatus2.returnNumber, "VoicemailStatus::returnNumber");
is(aStatus1.returnMessage, aStatus2.returnMessage, "VoicemailStatus::returnMessage");
}
/**
* Check if attributs of a VoicemailStatus match our expectations.
*/
function checkVoicemailStatus(aStatus, aServiceId, aHasMessages, aMessageCount,
aReturnNumber, aReturnMessage) {
compareVoicemailStatus(aStatus, {
serviceId: aServiceId,
hasMessages: aHasMessages,
messageCount: aMessageCount,
returnNumber: aReturnNumber,
returnMessage: aReturnMessage
});
}
/**
* Wait for pending emulator transactions and call |finish()|.
*/
function cleanUp() {
ok(true, ":: CLEANING UP ::");
waitFor(finish, function() {
return pendingEmulatorCmdCount === 0;
});
}
/**
* Basic test routine helper for voicemail tests.
*
* This helper does nothing but clean-ups.
*
* @param aTestCaseMain
* A function that takes no parameter.
*/
function startTestBase(aTestCaseMain) {
Promise.resolve()
.then(aTestCaseMain)
.then(cleanUp, function() {
ok(false, 'promise rejects during test.');
cleanUp();
});
}
/**
* Common test routine helper for voicemail tests.
*
* This function ensures global |voicemail| variable is available during the
* process and performs clean-ups as well.
*
* @param aTestCaseMain
* A function that takes no parameter.
*/
function startTestCommon(aTestCaseMain) {
startTestBase(function() {
return ensureVoicemail()
.then(aTestCaseMain);
});
}

View File

@ -3,6 +3,6 @@ b2g = true
browser = false
qemu = true
[test_voicemail_statuschanged.py]
[test_voicemail_statuschanged.js]
[test_voicemail_number.js]
[test_dsds_default_service_id.js]

View File

@ -1,149 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let RIL = {};
SpecialPowers.Cu.import("resource://gre/modules/ril_consts.js", RIL);
// Only bring in what we need from ril_worker/RadioInterfaceLayer here. Reusing
// that code turns out to be a nightmare, so there is some code duplication.
let PDUBuilder = {
toHexString: function(n, length) {
let str = n.toString(16);
if (str.length < length) {
for (let i = 0; i < length - str.length; i++) {
str = "0" + str;
}
}
return str.toUpperCase();
},
writeUint16: function(value) {
this.buf += (value & 0xff).toString(16).toUpperCase();
this.buf += ((value >> 8) & 0xff).toString(16).toUpperCase();
},
writeHexOctet: function(octet) {
this.buf += this.toHexString(octet, 2);
},
writeSwappedNibbleBCD: function(data) {
data = data.toString();
let zeroCharCode = '0'.charCodeAt(0);
for (let i = 0; i < data.length; i += 2) {
let low = data.charCodeAt(i) - zeroCharCode;
let high;
if (i + 1 < data.length) {
high = data.charCodeAt(i + 1) - zeroCharCode;
} else {
high = 0xF;
}
this.writeHexOctet((high << 4) | low);
}
},
writeStringAsSeptets: function(message, paddingBits, langIndex,
langShiftIndex) {
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
let dataBits = paddingBits;
let data = 0;
for (let i = 0; i < message.length; i++) {
let septet = langTable.indexOf(message[i]);
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
continue;
}
if (septet >= 0) {
data |= septet << dataBits;
dataBits += 7;
} else {
septet = langShiftTable.indexOf(message[i]);
if (septet == -1) {
throw new Error(message[i] + " not in 7 bit alphabet "
+ langIndex + ":" + langShiftIndex + "!");
}
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
continue;
}
data |= RIL.PDU_NL_EXTENDED_ESCAPE << dataBits;
dataBits += 7;
data |= septet << dataBits;
dataBits += 7;
}
for (; dataBits >= 8; dataBits -= 8) {
this.writeHexOctet(data & 0xFF);
data >>>= 8;
}
}
if (dataBits != 0) {
this.writeHexOctet(data & 0xFF);
}
},
buildAddress: function(address) {
let addressFormat = RIL.PDU_TOA_ISDN; // 81
if (address[0] == '+') {
addressFormat = RIL.PDU_TOA_INTERNATIONAL | RIL.PDU_TOA_ISDN; // 91
address = address.substring(1);
}
this.buf = "";
this.writeHexOctet(address.length);
this.writeHexOctet(addressFormat);
this.writeSwappedNibbleBCD(address);
return this.buf;
},
// assumes 7 bit encoding
buildUserData: function(options) {
let headerLength = 0;
this.buf = "";
if (options.headers) {
for each (let header in options.headers) {
headerLength += 2; // id + length octets
if (header.octets) {
headerLength += header.octets.length;
}
};
}
let encodedBodyLength = options.body.length;
let headerOctets = (headerLength ? headerLength + 1 : 0);
let paddingBits;
let userDataLengthInSeptets;
let headerSeptets = Math.ceil(headerOctets * 8 / 7);
userDataLengthInSeptets = headerSeptets + encodedBodyLength;
paddingBits = headerSeptets * 7 - headerOctets * 8;
this.writeHexOctet(userDataLengthInSeptets);
if (options.headers) {
this.writeHexOctet(headerLength);
for each (let header in options.headers) {
this.writeHexOctet(header.id);
this.writeHexOctet(header.length);
if (header.octets) {
for each (let octet in header.octets) {
this.writeHexOctet(octet);
}
}
}
}
this.writeStringAsSeptets(options.body, paddingBits,
RIL.PDU_NL_IDENTIFIER_DEFAULT,
RIL.PDU_NL_IDENTIFIER_DEFAULT);
return this.buf;
}
};

View File

@ -6,20 +6,21 @@ MARIONETTE_CONTEXT = "chrome";
Cu.import("resource://gre/modules/Promise.jsm");
const VOICEMAIL_PROVIDER_CONTRACTID = "@mozilla.org/ril/content-helper;1";
const VOICEMAIL_SERVICE_CONTRACTID =
"@mozilla.org/voicemail/gonkvoicemailservice;1";
const PREF_RIL_NUM_RADIO_INTERFACES = "ril.numRadioInterfaces";
const PREF_DEFAULT_SERVICE_ID = "dom.voicemail.defaultServiceId";
function setPrefAndVerify(prefKey, setVal, service, attrName, expectedVal, deferred) {
function setPrefAndVerify(prefKey, setVal, service, expectedVal, deferred) {
log(" Set '" + prefKey + "' to " + setVal);
Services.prefs.setIntPref(prefKey, setVal);
let prefVal = Services.prefs.getIntPref(prefKey);
is(prefVal, setVal, "'" + prefKey + "' set to " + setVal);
window.setTimeout(function() {
let defaultVal = service[attrName];
is(defaultVal, expectedVal, attrName);
let defaultVal = service.getDefaultItem().serviceId;
is(defaultVal, expectedVal, "serviceId");
deferred.resolve(service);
}, 0);
@ -52,7 +53,7 @@ function getService(contractId, ifaceName) {
return deferred.promise;
}
function checkInitialEquality(attrName, prefKey, service) {
function checkInitialEquality(prefKey, service) {
let deferred = Promise.defer();
log(" Checking initial value for '" + prefKey + "'");
@ -60,8 +61,8 @@ function checkInitialEquality(attrName, prefKey, service) {
ok(isFinite(origPrefVal), "default '" + prefKey + "' value");
window.setTimeout(function() {
let defaultVal = service[attrName];
is(defaultVal, origPrefVal, attrName);
let defaultVal = service.getDefaultItem().serviceId;
is(defaultVal, origPrefVal, "serviceId");
deferred.resolve(service);
}, 0);
@ -69,30 +70,30 @@ function checkInitialEquality(attrName, prefKey, service) {
return deferred.promise;
}
function checkSetToNegtiveValue(attrName, prefKey, service) {
function checkSetToNegtiveValue(prefKey, service) {
let deferred = Promise.defer();
// Set to -1 and verify defaultVal == 0.
setPrefAndVerify(prefKey, -1, service, attrName, 0, deferred);
setPrefAndVerify(prefKey, -1, service, 0, deferred);
return deferred.promise;
}
function checkSetToOverflowedValue(attrName, prefKey, numRil, service) {
function checkSetToOverflowedValue(prefKey, numRil, service) {
let deferred = Promise.defer();
// Set to larger-equal than numRil and verify defaultVal == 0.
setPrefAndVerify(prefKey, numRil, service, attrName, 0, deferred);
setPrefAndVerify(prefKey, numRil, service, 0, deferred);
return deferred.promise;
}
function checkValueChange(attrName, prefKey, numRil, service) {
function checkValueChange(prefKey, numRil, service) {
let deferred = Promise.defer();
if (numRil > 1) {
// Set to (numRil - 1) and verify defaultVal equals.
setPrefAndVerify(prefKey, numRil - 1, service, attrName, numRil - 1, deferred);
setPrefAndVerify(prefKey, numRil - 1, service, numRil - 1, deferred);
} else {
window.setTimeout(function() {
deferred.resolve(service);
@ -102,14 +103,14 @@ function checkValueChange(attrName, prefKey, numRil, service) {
return deferred.promise;
}
function verify(contractId, ifaceName, attrName, prefKey, numRil) {
function verify(contractId, ifaceName, prefKey, numRil) {
let deferred = Promise.defer();
getService(contractId, ifaceName)
.then(checkInitialEquality.bind(null, attrName, prefKey))
.then(checkSetToNegtiveValue.bind(null, attrName, prefKey))
.then(checkSetToOverflowedValue.bind(null, attrName, prefKey, numRil))
.then(checkValueChange.bind(null, attrName, prefKey, numRil))
.then(checkInitialEquality.bind(null, prefKey))
.then(checkSetToNegtiveValue.bind(null, prefKey))
.then(checkSetToOverflowedValue.bind(null, prefKey, numRil))
.then(checkValueChange.bind(null, prefKey, numRil))
.then(function() {
// Reset.
Services.prefs.clearUserPref(prefKey);
@ -121,6 +122,6 @@ function verify(contractId, ifaceName, attrName, prefKey, numRil) {
}
getNumRadioInterfaces()
.then(verify.bind(null, VOICEMAIL_PROVIDER_CONTRACTID, "nsIVoicemailProvider",
"voicemailDefaultServiceId", PREF_DEFAULT_SERVICE_ID))
.then(verify.bind(null, VOICEMAIL_SERVICE_CONTRACTID, "nsIVoicemailService",
PREF_DEFAULT_SERVICE_ID))
.then(finish);

View File

@ -1,21 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 10000;
const MARIONETTE_TIMEOUT = 60000;
const MARIONETTE_HEAD_JS = 'head.js';
SpecialPowers.addPermission("voicemail", true, document);
startTestCommon(function() {
let serviceId = 0;
let voicemail = window.navigator.mozVoicemail;
ok(voicemail instanceof MozVoicemail);
// These are the emulator's hard coded voicemail number and alphaId
is(voicemail.getNumber(serviceId), "+15552175049");
is(voicemail.getDisplayName(serviceId), "Voicemail");
let serviceId = 0;
// These are the emulator's hard coded voicemail number and alphaId
is(voicemail.getNumber(serviceId), "+15552175049");
is(voicemail.getDisplayName(serviceId), "Voicemail");
is(voicemail.getNumber(), "+15552175049");
is(voicemail.getDisplayName(), "Voicemail");
SpecialPowers.removePermission("voicemail", document);
finish();
is(voicemail.getNumber(), "+15552175049");
is(voicemail.getDisplayName(), "Voicemail");
});

View File

@ -1,208 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
SpecialPowers.addPermission("voicemail", true, document);
let voicemail = window.navigator.mozVoicemail;
let serviceId = 0;
ok(voicemail instanceof MozVoicemail);
is(voicemail.status, null);
function sendIndicatorPDU(pdu, listener, nextTest) {
let smsCommand = "sms pdu " + pdu;
let commandCompleted = false;
let sawEvent = false;
voicemail.addEventListener("statuschanged", function statusChanged(event) {
voicemail.removeEventListener("statuschanged", statusChanged);
try {
listener(event);
} catch (e) {
ok(false, String(e));
}
sawEvent = true;
if (commandCompleted) {
nextTest();
}
});
log("-> " + smsCommand);
runEmulatorCmd(smsCommand, function(result) {
log("<- " + result);
is(result[0], "OK");
commandCompleted = true;
if (sawEvent) {
nextTest();
}
});
}
const MARIONETTE_TIMEOUT = 60000;
const MARIONETTE_HEAD_JS = 'head.js';
// TODO: Add tests for store/discard once they are implemented
// See RadioInterfaceLayer.js / Bug #768441
function isVoicemailStatus(status) {
is(voicemail.getStatus(), status);
is(voicemail.getStatus(serviceId), status);
function checkEventStatus(aEvent, aServiceId, aHasMessages, aMessageCount,
aReturnNumber, aReturnMessage) {
let status = aEvent.status;
ok(true, "status = " + JSON.stringify(status));
ok(status instanceof MozVoicemailStatus);
is(voicemail.getStatus().hasMessages, status.hasMessages);
is(voicemail.getStatus().messageCount, status.messageCount);
is(voicemail.getStatus().returnNumber, status.returnNumber);
is(voicemail.getStatus().returnMessage, status.returnMessage);
checkVoicemailStatus(status, 0, aHasMessages, aMessageCount, aReturnNumber,
aReturnMessage);
compareVoicemailStatus(voicemail.getStatus(0), status);
compareVoicemailStatus(voicemail.getStatus(), status);
}
const MWI_PDU_PREFIX = "0000";
const MWI_PDU_UDH_PREFIX = "0040";
const MWI_PID_DEFAULT = "00";
const MWI_DCS_DISCARD_INACTIVE = "C0";
const MWI_DCS_DISCARD_ACTIVE = "C8";
const MWI_TIMESTAMP = "00000000000000";
const MWI_DEFAULT_BODY = "1 new voicemail";
const MWI_UD_DEFAULT = PDUBuilder.buildUserData({
body: MWI_DEFAULT_BODY
});
const MWI_LEVEL2_SENDER = "+15125551235";
const MWI_LEVEL2_PDU_ADDRESS = PDUBuilder.buildAddress(MWI_LEVEL2_SENDER);
const MWI_LEVEL2_DISCARD_ACTIVE_PDU =
MWI_PDU_PREFIX +
MWI_LEVEL2_PDU_ADDRESS +
MWI_PID_DEFAULT +
MWI_DCS_DISCARD_ACTIVE +
MWI_TIMESTAMP +
MWI_UD_DEFAULT;
function testLevel2DiscardActive() {
function onLevel2Active(event) {
let status = event.status;
// TODO: bug 905228 - MozVoicemailStatus is not defined.
//ok(status instanceof MozVoicemailStatus);
is(status.hasMessages, true);
is(status.messageCount, -1);
is(status.returnNumber, MWI_LEVEL2_SENDER);
is(status.returnMessage, MWI_DEFAULT_BODY);
isVoicemailStatus(status);
}
sendIndicatorPDU(MWI_LEVEL2_DISCARD_ACTIVE_PDU,
onLevel2Active,
testLevel2DiscardInactive);
function testLevel2DiscardActive(aActive) {
log(" Active: " + aActive);
let sender = "+15125551235";
let body = "1 new voicemail";
let pdu = PDUBuilder.buildLevel2DiscardMwi(aActive, sender, body);
return sendIndicatorPDUAndWait(pdu)
.then((aResults) => checkEventStatus(aResults[0], 0, aActive,
(aActive ? -1 : 0), sender, body));
}
const MWI_LEVEL2_DISCARD_INACTIVE_PDU =
MWI_PDU_PREFIX +
MWI_LEVEL2_PDU_ADDRESS +
MWI_PID_DEFAULT +
MWI_DCS_DISCARD_INACTIVE +
MWI_TIMESTAMP +
MWI_UD_DEFAULT;
function testLevel2DiscardInactive() {
function onLevel2Inactive(event) {
let status = event.status;
// TODO: bug 905228 - MozVoicemailStatus is not defined.
//ok(status instanceof MozVoicemailStatus);
is(status.hasMessages, false);
is(status.messageCount, 0);
is(status.returnNumber, MWI_LEVEL2_SENDER);
is(status.returnMessage, MWI_DEFAULT_BODY);
isVoicemailStatus(status);
}
sendIndicatorPDU(MWI_LEVEL2_DISCARD_INACTIVE_PDU,
onLevel2Inactive,
testLevel3DiscardActive);
}
// Tests for Level 3 MWI with a message count in the User Data Header
const MWI_LEVEL3_SENDER = "+15125551236";
const MWI_LEVEL3_PDU_ADDRESS = PDUBuilder.buildAddress(MWI_LEVEL3_SENDER);
function testLevel3DiscardActive(aMessageCount) {
log(" Message Count: " + aMessageCount);
const MWI_LEVEL3_ACTIVE_UDH_MSG_COUNT = 3;
const MWI_LEVEL3_ACTIVE_BODY = "3 new voicemails";
const MWI_LEVEL3_ACTIVE_UD = PDUBuilder.buildUserData({
headers: [{
id: RIL.PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION,
length: 2,
octets: [
RIL.PDU_MWI_STORE_TYPE_DISCARD,
MWI_LEVEL3_ACTIVE_UDH_MSG_COUNT
]
}],
body: MWI_LEVEL3_ACTIVE_BODY
let sender = "+15125551236";
let body = aMessageCount + " voicemails";
let pdu = PDUBuilder.buildLevel3DiscardMwi(aMessageCount, sender, body);
return sendIndicatorPDUAndWait(pdu)
.then((aResults) => checkEventStatus(aResults[0], 0, !!aMessageCount,
aMessageCount, sender, body));
}
startTestCommon(function() {
return Promise.resolve()
.then(() => log("Testing Message Waiting Indication Group"))
// Level 2 discarded active/inactive MWI.
.then(() => log(" Discard Message"))
.then(() => testLevel2DiscardActive(true))
.then(() => testLevel2DiscardActive(false))
.then(() => log("Testing Special SMS Message Indication"))
.then(() => log(" Discard Message"))
// Level 3 discarded active/inactive MWI.
.then(() => testLevel3DiscardActive(3))
.then(() => testLevel3DiscardActive(0));
});
const MWI_LEVEL3_DISCARD_ACTIVE_PDU =
MWI_PDU_UDH_PREFIX +
MWI_LEVEL3_PDU_ADDRESS +
MWI_PID_DEFAULT +
MWI_DCS_DISCARD_ACTIVE +
MWI_TIMESTAMP +
MWI_LEVEL3_ACTIVE_UD;
function testLevel3DiscardActive() {
function onLevel3Active(event) {
let status = event.status;
// TODO: bug 905228 - MozVoicemailStatus is not defined.
//ok(status instanceof MozVoicemailStatus);
is(status.hasMessages, true);
is(status.messageCount, MWI_LEVEL3_ACTIVE_UDH_MSG_COUNT);
is(status.returnNumber, MWI_LEVEL3_SENDER);
is(status.returnMessage, MWI_LEVEL3_ACTIVE_BODY);
isVoicemailStatus(status);
}
sendIndicatorPDU(MWI_LEVEL3_DISCARD_ACTIVE_PDU,
onLevel3Active,
testLevel3DiscardInactive);
}
const MWI_LEVEL3_INACTIVE_BODY = "No unread voicemails";
const MWI_LEVEL3_INACTIVE_UD = PDUBuilder.buildUserData({
headers: [{
id: RIL.PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION,
length: 2,
octets: [
RIL.PDU_MWI_STORE_TYPE_DISCARD,
0 // messageCount
]
}],
body: MWI_LEVEL3_INACTIVE_BODY
});
const MWI_LEVEL3_DISCARD_INACTIVE_PDU =
MWI_PDU_UDH_PREFIX +
MWI_LEVEL3_PDU_ADDRESS +
MWI_PID_DEFAULT +
MWI_DCS_DISCARD_ACTIVE +
MWI_TIMESTAMP +
MWI_LEVEL3_INACTIVE_UD;
function testLevel3DiscardInactive() {
function onLevel3Inactive(event) {
let status = event.status;
// TODO: bug 905228 - MozVoicemailStatus is not defined.
//ok(status instanceof MozVoicemailStatus);
is(status.hasMessages, false);
is(status.messageCount, 0);
is(status.returnNumber, MWI_LEVEL3_SENDER);
is(status.returnMessage, MWI_LEVEL3_INACTIVE_BODY);
isVoicemailStatus(status);
}
sendIndicatorPDU(MWI_LEVEL3_DISCARD_INACTIVE_PDU, onLevel3Inactive, cleanUp);
}
function cleanUp() {
SpecialPowers.removePermission("voicemail", document);
finish();
}
testLevel2DiscardActive();

View File

@ -1,14 +0,0 @@
from marionette_test import MarionetteTestCase
import os
class TestVoicemailStatusChanged(MarionetteTestCase):
def testStatusChanged(self):
this_dir = os.path.abspath(os.path.dirname(__file__))
pdu_builder_path = os.path.join(this_dir, "pdu_builder.js")
self.marionette.import_script(pdu_builder_path)
test_path = os.path.join(this_dir, "test_voicemail_statuschanged.js")
test = open(test_path, "r").read()
self.marionette.set_script_timeout(30000)
self.marionette.execute_async_script(test)

View File

@ -298,6 +298,10 @@ interface CameraControl : MediaStream
[Pref="camera.control.autofocus_moving_callback.enabled"]
attribute CameraAutoFocusMovingCallback? onAutoFocusMoving;
/* this function is called whenever auto focus completes, due to continuous
autofocus or a solicited auto focus. */
attribute CameraAutoFocusCallback? onAutoFocusCompleted;
/* capture an image and return it as a blob to the 'onSuccess' callback;
if the camera supports it, this may be invoked while the camera is
already recording video.

View File

@ -4,9 +4,7 @@
* 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/. */
[JSImplementation="@mozilla.org/voicemailstatus;1",
Pref="dom.voicemail.enabled"]
[Pref="dom.voicemail.enabled"]
interface MozVoicemailStatus
{
readonly attribute unsigned long serviceId;

View File

@ -275,6 +275,8 @@ WEBIDL_FILES = [
'MozSelfSupport.webidl',
'MozTetheringManager.webidl',
'MozTimeManager.webidl',
'MozVoicemail.webidl',
'MozVoicemailStatus.webidl',
'MozWakeLock.webidl',
'MutationEvent.webidl',
'MutationObserver.webidl',
@ -605,8 +607,6 @@ if CONFIG['MOZ_B2G_RIL']:
'MozCellBroadcast.webidl',
'MozIcc.webidl',
'MozIccManager.webidl',
'MozVoicemail.webidl',
'MozVoicemailStatus.webidl'
]
if CONFIG['MOZ_NFC']:
@ -672,6 +672,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'MozSettingsTransactionEvent.webidl',
'MozSmsEvent.webidl',
'MozStkCommandEvent.webidl',
'MozVoicemailEvent.webidl',
'PageTransitionEvent.webidl',
'PopStateEvent.webidl',
'PopupBlockedEvent.webidl',
@ -725,7 +726,6 @@ if CONFIG['MOZ_B2G_BT']:
if CONFIG['MOZ_B2G_RIL']:
GENERATED_EVENTS_WEBIDL_FILES += [
'MozCellBroadcastEvent.webidl',
'MozVoicemailEvent.webidl',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':

View File

@ -234,6 +234,7 @@ static void Shutdown();
#include "StreamingProtocolService.h"
#include "nsITelephonyService.h"
#include "nsIVoicemailService.h"
#ifdef MOZ_WIDGET_GONK
#include "GonkGPSGeolocationProvider.h"
@ -352,6 +353,8 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIMobileConnectionService,
NS_CreateMobileConnectionService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsITelephonyService,
NS_CreateTelephonyService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIVoicemailService,
NS_CreateVoicemailService)
//-----------------------------------------------------------------------------
@ -790,6 +793,7 @@ NS_DEFINE_NAMED_CID(NS_SYNTHVOICEREGISTRY_CID);
NS_DEFINE_NAMED_CID(NS_ACCESSIBILITY_SERVICE_CID);
#endif
NS_DEFINE_NAMED_CID(TELEPHONY_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_VOICEMAIL_SERVICE_CID);
NS_DEFINE_NAMED_CID(GECKO_MEDIA_PLUGIN_SERVICE_CID);
@ -1079,6 +1083,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
#endif
{ &kTELEPHONY_SERVICE_CID, false, nullptr, nsITelephonyServiceConstructor },
{ &kNS_MOBILE_CONNECTION_SERVICE_CID, false, NULL, nsIMobileConnectionServiceConstructor },
{ &kNS_VOICEMAIL_SERVICE_CID, false, nullptr, nsIVoicemailServiceConstructor },
{ nullptr }
};
@ -1237,6 +1242,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
{ TELEPHONY_SERVICE_CONTRACTID, &kTELEPHONY_SERVICE_CID },
{ "@mozilla.org/gecko-media-plugin-service;1", &kGECKO_MEDIA_PLUGIN_SERVICE_CID },
{ NS_MOBILE_CONNECTION_SERVICE_CONTRACTID, &kNS_MOBILE_CONNECTION_SERVICE_CID },
{ NS_VOICEMAIL_SERVICE_CONTRACTID, &kNS_VOICEMAIL_SERVICE_CID },
{ nullptr }
};

View File

@ -1181,8 +1181,6 @@ public abstract class GeckoApp
GeckoAppShell.setContextGetter(this);
GeckoAppShell.setGeckoInterface(this);
ThreadUtils.setUiThread(Thread.currentThread(), new Handler());
Tabs.getInstance().attachToContext(this);
try {
Favicons.initializeWithContext(this);

View File

@ -166,7 +166,6 @@ public class GeckoView extends LayerView
EventDispatcher.getInstance().registerGeckoThreadListener(mNativeEventListener,
"Accessibility:Ready");
ThreadUtils.setUiThread(Thread.currentThread(), new Handler());
initializeView(EventDispatcher.getInstance());
if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {

View File

@ -10,6 +10,7 @@ import org.mozilla.gecko.mozglue.RobocopTarget;
import java.util.Map;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
@ -25,10 +26,10 @@ public final class ThreadUtils {
THROW,
}
private static volatile Thread sUiThread;
private static volatile Thread sBackgroundThread;
private static final Thread sUiThread = Looper.getMainLooper().getThread();
private static final Handler sUiHandler = new Handler(Looper.getMainLooper());
private static Handler sUiHandler;
private static volatile Thread sBackgroundThread;
// Referenced directly from GeckoAppShell in highly performance-sensitive code (The extra
// function call of the getter was harming performance. (Bug 897123))
@ -79,11 +80,6 @@ public final class ThreadUtils {
}
}
public static void setUiThread(Thread thread, Handler handler) {
sUiThread = thread;
sUiHandler = handler;
}
public static void setBackgroundThread(Thread thread) {
sBackgroundThread = thread;
}

View File

@ -1574,7 +1574,10 @@ SpecialPowersAPI.prototype = {
var xferable = Components.classes["@mozilla.org/widget/transferable;1"].
createInstance(Components.interfaces.nsITransferable);
xferable.init(this._getDocShell(content.window)
// in e10s b-c tests |content.window| is null whereas |window| works fine.
// for some non-e10s mochi tests, |window| is null whereas |content.window|
// works fine. So we take whatever is non-null!
xferable.init(this._getDocShell(content.window || window)
.QueryInterface(Components.interfaces.nsILoadContext));
xferable.addDataFlavor(flavor);
this._cb.getData(xferable, whichClipboard);

View File

@ -1,5 +1,4 @@
[DEFAULT]
skip-if = e10s
[browser_passwordmgr_fields.js]
[browser_passwordmgr_observers.js]

View File

@ -25,6 +25,16 @@ const SearchAutocompleteProviderInternal = {
*/
priorityMatches: null,
/**
* Array of objects in the format returned by findMatchByAlias.
*/
aliasMatches: null,
/**
* Object for the default search match.
**/
defaultMatch: null,
initialize: function () {
return new Promise((resolve, reject) => {
Services.search.init(status => {
@ -60,6 +70,17 @@ const SearchAutocompleteProviderInternal = {
_refresh: function () {
this.priorityMatches = [];
this.aliasMatches = [];
this.defaultMatch = null;
let currentEngine = Services.search.currentEngine;
// This can be null in XCPShell.
if (currentEngine) {
this.defaultMatch = {
engineName: currentEngine.name,
iconUrl: currentEngine.iconURI ? currentEngine.iconURI.spec : null,
}
}
// The search engines will always be processed in the order returned by the
// search service, which can be defined by the user.
@ -67,19 +88,25 @@ const SearchAutocompleteProviderInternal = {
},
_addEngine: function (engine) {
let token = engine.getResultDomain();
if (!token) {
return;
if (engine.alias) {
this.aliasMatches.push({
alias: engine.alias,
engineName: engine.name,
iconUrl: engine.iconURI ? engine.iconURI.spec : null,
});
}
this.priorityMatches.push({
token: token,
// The searchForm property returns a simple URL for the search engine, but
// we may need an URL which includes an affiliate code (bug 990799).
url: engine.searchForm,
engineName: engine.name,
iconUrl: engine.iconURI ? engine.iconURI.spec : null,
});
let domain = engine.getResultDomain();
if (domain) {
this.priorityMatches.push({
token: domain,
// The searchForm property returns a simple URL for the search engine, but
// we may need an URL which includes an affiliate code (bug 990799).
url: engine.searchForm,
engineName: engine.name,
iconUrl: engine.iconURI ? engine.iconURI.spec : null,
});
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
@ -123,7 +150,36 @@ this.PlacesSearchAutocompleteProvider = Object.freeze({
// Match at the beginning for now. In the future, an "options" argument may
// allow the matching behavior to be tuned.
return SearchAutocompleteProviderInternal.priorityMatches
.find(m => m.token.startsWith(searchToken));
.find(m => m.token.startsWith(searchToken));
}),
/**
* Matches a given search string to an item that should be included by
* components wishing to search using search engine aliases, like
* autocomple.
*
* @param searchToken
* Search string to match exactly a search engine alias.
*
* @return An object with the following properties, or undefined if the token
* does not match any relevant URL:
* {
* alias: The matched search engine's alias.
* engineName: The display name of the search engine.
* iconUrl: Icon associated to the match, or null if not available.
* }
*/
findMatchByAlias: Task.async(function* (searchToken) {
yield this.ensureInitialized();
return SearchAutocompleteProviderInternal.aliasMatches
.find(m => m.alias == searchToken);
}),
getDefaultMatch: Task.async(function* () {
yield this.ensureInitialized();
return SearchAutocompleteProviderInternal.defaultMatch;
}),
/**

View File

@ -706,6 +706,12 @@ Search.prototype = {
hasFirstResult = true;
}
if (this._enableActions && !hasFirstResult) {
// If it's not a bookmarked keyword, then it may be a search engine
// with an alias - which works like a keyword.
hasFirstResult = yield this._matchSearchEngineAlias();
}
let shouldAutofill = this._shouldAutofill;
if (this.pending && !hasFirstResult && shouldAutofill) {
// Or it may look like a URL we know about from search engines.
@ -717,6 +723,11 @@ Search.prototype = {
hasFirstResult = yield this._matchKnownUrl(conn, queries);
}
if (this.pending && this._enableActions && !hasFirstResult) {
// When all else fails, we search using the current search engine.
yield this._matchCurrentSearchEngine();
}
yield this._sleep(Prefs.delay);
if (!this.pending)
return;
@ -828,6 +839,48 @@ Search.prototype = {
return true;
},
_matchSearchEngineAlias: function* () {
if (this._searchTokens.length < 2)
return false;
let match = yield PlacesSearchAutocompleteProvider.findMatchByAlias(
this._searchTokens[0]);
if (!match)
return false;
let query = this._searchTokens.slice(1).join(" ");
yield this._addSearchEngineMatch(match, query);
return true;
},
_matchCurrentSearchEngine: function* () {
let match = yield PlacesSearchAutocompleteProvider.getDefaultMatch();
if (!match)
return;
let query = this._originalSearchString;
yield this._addSearchEngineMatch(match, query);
},
_addSearchEngineMatch: function* (match, query) {
let value = makeActionURL("searchengine", {
engineName: match.engineName,
input: this._originalSearchString,
searchQuery: query,
});
this._addMatch({
value: value,
comment: match.engineName,
icon: match.iconUrl,
style: "action searchengine",
finalCompleteValue: this._trimmedOriginalSearchString,
frecency: FRECENCY_SEARCHENGINES_DEFAULT,
});
},
_onResultRow: function (row) {
TelemetryStopwatch.finish(TELEMETRY_1ST_RESULT);
let queryType = row.getResultByIndex(QUERYINDEX_QUERYTYPE);

View File

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(function*() {
Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET",
"http://s.example.com/search");
let engine = Services.search.getEngineByName("MozSearch");
Services.search.currentEngine = engine;
Services.search.addEngineWithDetails("AliasedMozSearch", "", "doit", "",
"GET", "http://s.example.com/search");
yield check_autocomplete({
search: "doit",
searchParam: "enable-actions",
matches: [ { uri: makeActionURI("searchengine", {engineName: "MozSearch", input: "doit", searchQuery: "doit"}), title: "MozSearch" }, ]
});
yield check_autocomplete({
search: "doit mozilla",
searchParam: "enable-actions",
matches: [ { uri: makeActionURI("searchengine", {engineName: "AliasedMozSearch", input: "doit mozilla", searchQuery: "mozilla"}), title: "AliasedMozSearch" }, ]
});
yield check_autocomplete({
search: "doit mozzarella mozilla",
searchParam: "enable-actions",
matches: [ { uri: makeActionURI("searchengine", {engineName: "AliasedMozSearch", input: "doit mozzarella mozilla", searchQuery: "mozzarella mozilla"}), title: "AliasedMozSearch" }, ]
});
yield cleanup();
});

View File

@ -0,0 +1,35 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(function*() {
Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET",
"http://s.example.com/search");
let engine = Services.search.getEngineByName("MozSearch");
Services.search.currentEngine = engine;
Services.search.addEngineWithDetails("AliasedMozSearch", "", "doit", "",
"GET", "http://s.example.com/search");
do_log_info("search engine");
yield check_autocomplete({
search: "mozilla",
searchParam: "enable-actions",
matches: [ { uri: makeActionURI("searchengine", {engineName: "MozSearch", input: "mozilla", searchQuery: "mozilla"}), title: "MozSearch" }, ]
});
do_log_info("search engine, uri-like input");
yield check_autocomplete({
search: "http:///",
searchParam: "enable-actions",
matches: [ { uri: makeActionURI("searchengine", {engineName: "MozSearch", input: "http:///", searchQuery: "http:///"}), title: "MozSearch" }, ]
});
do_log_info("search engine, multiple words");
yield check_autocomplete({
search: "mozzarella cheese",
searchParam: "enable-actions",
matches: [ { uri: makeActionURI("searchengine", {engineName: "MozSearch", input: "mozzarella cheese", searchQuery: "mozzarella cheese"}), title: "MozSearch" }, ]
});
yield cleanup();
});

Some files were not shown because too many files have changed in this diff Show More