mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-16 06:54:00 +00:00
merge b2g-inbound to mozilla-central a=merge
--HG-- extra : amend_source : 6e2548ed562a40244895d9c341546e09f46cb6f4
This commit is contained in:
commit
f7ad4b9ff3
@ -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="753732a370d2d0e4e45d5eceaa1c53c7d11a9f38"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="88e0a972280bb35847c010b8c3f1481fa80f3847"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -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="753732a370d2d0e4e45d5eceaa1c53c7d11a9f38"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="88e0a972280bb35847c010b8c3f1481fa80f3847"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="753732a370d2d0e4e45d5eceaa1c53c7d11a9f38"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="88e0a972280bb35847c010b8c3f1481fa80f3847"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -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="753732a370d2d0e4e45d5eceaa1c53c7d11a9f38"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="88e0a972280bb35847c010b8c3f1481fa80f3847"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -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="753732a370d2d0e4e45d5eceaa1c53c7d11a9f38"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="88e0a972280bb35847c010b8c3f1481fa80f3847"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "db540afcf32e30144e33555a5d6ca860ff8cabc3",
|
||||
"revision": "168c5ba3a072b6c6b30bcc93586f833cc97fff4a",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -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="753732a370d2d0e4e45d5eceaa1c53c7d11a9f38"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="88e0a972280bb35847c010b8c3f1481fa80f3847"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -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="753732a370d2d0e4e45d5eceaa1c53c7d11a9f38"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="88e0a972280bb35847c010b8c3f1481fa80f3847"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -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="753732a370d2d0e4e45d5eceaa1c53c7d11a9f38"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="88e0a972280bb35847c010b8c3f1481fa80f3847"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="aebf432f334ec0b48eb358569b9dfbfbead48017"/>
|
||||
|
@ -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="753732a370d2d0e4e45d5eceaa1c53c7d11a9f38"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="88e0a972280bb35847c010b8c3f1481fa80f3847"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9ff55cd0aefea23e4c60e5844c155c6ebc2e632b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -151,6 +151,13 @@ AudioChannelService::RegisterType(AudioChannel aChannel, uint64_t aChildID,
|
||||
mChannelCounters[type].AppendElement(aChildID);
|
||||
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||
|
||||
// We must keep the childIds in order to decide which app is allowed to play
|
||||
// with then telephony channel.
|
||||
if (aChannel == AudioChannel::Telephony) {
|
||||
RegisterTelephonyChild(aChildID);
|
||||
}
|
||||
|
||||
// Since there is another telephony registered, we can unregister old one
|
||||
// immediately.
|
||||
if (mDeferTelChannelTimer && aChannel == AudioChannel::Telephony) {
|
||||
@ -234,15 +241,21 @@ AudioChannelService::UnregisterType(AudioChannel aChannel,
|
||||
// There are two reasons to defer the decrease of telephony channel.
|
||||
// 1. User can have time to remove device from his ear before music resuming.
|
||||
// 2. Give BT SCO to be disconnected before starting to connect A2DP.
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Default &&
|
||||
aChannel == AudioChannel::Telephony &&
|
||||
(mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN].Length() +
|
||||
mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY].Length()) == 1) {
|
||||
mTimerElementHidden = aElementHidden;
|
||||
mTimerChildID = aChildID;
|
||||
mDeferTelChannelTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mDeferTelChannelTimer->InitWithCallback(this, 1500, nsITimer::TYPE_ONE_SHOT);
|
||||
return;
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||
|
||||
if (aChannel == AudioChannel::Telephony) {
|
||||
UnregisterTelephonyChild(aChildID);
|
||||
}
|
||||
|
||||
if (aChannel == AudioChannel::Telephony &&
|
||||
(mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN].Length() +
|
||||
mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY].Length()) == 1) {
|
||||
mTimerElementHidden = aElementHidden;
|
||||
mTimerChildID = aChildID;
|
||||
mDeferTelChannelTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mDeferTelChannelTimer->InitWithCallback(this, 1500, nsITimer::TYPE_ONE_SHOT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UnregisterTypeInternal(aChannel, aElementHidden, aChildID, aWithVideo);
|
||||
@ -358,7 +371,7 @@ AudioChannelService::GetStateInternal(AudioChannel aChannel, uint64_t aChildID,
|
||||
if (CheckVolumeFadedCondition(newType, aElementHidden)) {
|
||||
return AUDIO_CHANNEL_STATE_FADED;
|
||||
}
|
||||
return AUDIO_CHANNEL_STATE_NORMAL;
|
||||
return CheckTelephonyPolicy(aChannel, aChildID);
|
||||
}
|
||||
|
||||
// We are not visible, maybe we have to mute.
|
||||
@ -387,7 +400,34 @@ AudioChannelService::GetStateInternal(AudioChannel aChannel, uint64_t aChildID,
|
||||
return AUDIO_CHANNEL_STATE_MUTED;
|
||||
}
|
||||
|
||||
return AUDIO_CHANNEL_STATE_NORMAL;
|
||||
return CheckTelephonyPolicy(aChannel, aChildID);
|
||||
}
|
||||
|
||||
AudioChannelState
|
||||
AudioChannelService::CheckTelephonyPolicy(AudioChannel aChannel,
|
||||
uint64_t aChildID)
|
||||
{
|
||||
// Only the latest childID is allowed to play with telephony channel.
|
||||
if (aChannel != AudioChannel::Telephony) {
|
||||
return AUDIO_CHANNEL_STATE_NORMAL;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mTelephonyChildren.IsEmpty());
|
||||
|
||||
#if DEBUG
|
||||
bool found = false;
|
||||
for (uint32_t i = 0, len = mTelephonyChildren.Length(); i < len; ++i) {
|
||||
if (mTelephonyChildren[i].mChildID == aChildID) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(found);
|
||||
#endif
|
||||
|
||||
return mTelephonyChildren.LastElement().mChildID == aChildID
|
||||
? AUDIO_CHANNEL_STATE_NORMAL : AUDIO_CHANNEL_STATE_MUTED;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -986,3 +1026,39 @@ AudioChannelService::GetDefaultAudioChannelString(nsAString& aString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::RegisterTelephonyChild(uint64_t aChildID)
|
||||
{
|
||||
for (uint32_t i = 0, len = mTelephonyChildren.Length(); i < len; ++i) {
|
||||
if (mTelephonyChildren[i].mChildID == aChildID) {
|
||||
++mTelephonyChildren[i].mInstances;
|
||||
|
||||
if (i != len - 1) {
|
||||
TelephonyChild child = mTelephonyChildren[i];
|
||||
mTelephonyChildren.RemoveElementAt(i);
|
||||
mTelephonyChildren.AppendElement(child);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mTelephonyChildren.AppendElement(TelephonyChild(aChildID));
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::UnregisterTelephonyChild(uint64_t aChildID)
|
||||
{
|
||||
for (uint32_t i = 0, len = mTelephonyChildren.Length(); i < len; ++i) {
|
||||
if (mTelephonyChildren[i].mChildID == aChildID) {
|
||||
if (!--mTelephonyChildren[i].mInstances) {
|
||||
mTelephonyChildren.RemoveElementAt(i);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "This should not happen.");
|
||||
}
|
||||
|
@ -150,6 +150,11 @@ protected:
|
||||
void SetDefaultVolumeControlChannelInternal(int32_t aChannel,
|
||||
bool aHidden, uint64_t aChildID);
|
||||
|
||||
AudioChannelState CheckTelephonyPolicy(AudioChannel aChannel,
|
||||
uint64_t aChildID);
|
||||
void RegisterTelephonyChild(uint64_t aChildID);
|
||||
void UnregisterTelephonyChild(uint64_t aChildID);
|
||||
|
||||
AudioChannelService();
|
||||
virtual ~AudioChannelService();
|
||||
|
||||
@ -225,6 +230,19 @@ protected:
|
||||
|
||||
nsTArray<uint64_t> mWithVideoChildIDs;
|
||||
|
||||
// Telephony Channel policy is "LIFO", the last app to require the resource is
|
||||
// allowed to play. The others are muted.
|
||||
struct TelephonyChild {
|
||||
uint64_t mChildID;
|
||||
uint32_t mInstances;
|
||||
|
||||
explicit TelephonyChild(uint64_t aChildID)
|
||||
: mChildID(aChildID)
|
||||
, mInstances(1)
|
||||
{}
|
||||
};
|
||||
nsTArray<TelephonyChild> mTelephonyChildren;
|
||||
|
||||
// mPlayableHiddenContentChildID stores the ChildID of the process which can
|
||||
// play content channel(s) in the background.
|
||||
// A background process contained content channel(s) will become playable:
|
||||
|
BIN
dom/audiochannel/tests/audio.ogg
Normal file
BIN
dom/audiochannel/tests/audio.ogg
Normal file
Binary file not shown.
18
dom/audiochannel/tests/file_telephonyPolicy.html
Normal file
18
dom/audiochannel/tests/file_telephonyPolicy.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test Telephony Channel Policy</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var audio = new Audio();
|
||||
audio.mozAudioChannelType = 'telephony';
|
||||
audio.src = "audio.ogg";
|
||||
audio.play();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,7 +1,11 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
audio.ogg
|
||||
file_audio.html
|
||||
file_telephonyPolicy.html
|
||||
AudioChannelChromeScript.js
|
||||
|
||||
[test_telephonyPolicy.html]
|
||||
skip-if = (toolkit == 'gonk' || e10s)
|
||||
[test_audioChannelChange.html]
|
||||
skip-if = (toolkit != 'gonk')
|
||||
|
85
dom/audiochannel/tests/test_telephonyPolicy.html
Normal file
85
dom/audiochannel/tests/test_telephonyPolicy.html
Normal file
@ -0,0 +1,85 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test the Telephony Channel Policy</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function mainApp() {
|
||||
var audio = new Audio();
|
||||
audio.mozAudioChannelType = 'telephony';
|
||||
audio.src = "audio.ogg";
|
||||
audio.loop = true;
|
||||
audio.play();
|
||||
|
||||
audio.addEventListener('mozinterruptbegin', function() {
|
||||
ok(true, "This element has been muted!");
|
||||
}, false);
|
||||
|
||||
audio.addEventListener('mozinterruptend', function() {
|
||||
ok(true, "This element has been unmuted!");
|
||||
audio.pause();
|
||||
runTest();
|
||||
}, false);
|
||||
|
||||
setTimeout(runTest, 600);
|
||||
}
|
||||
|
||||
function newApp() {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('mozbrowser', true);
|
||||
// That needs to be an app.
|
||||
iframe.setAttribute('mozapp', 'https://acertified.com/manifest.webapp');
|
||||
iframe.src = "file_telephonyPolicy.html";
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Permissions
|
||||
function() {
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "browser", "allow": 1, "context": document },
|
||||
{ "type": "embed-apps", "allow": 1, "context": document },
|
||||
{ "type": "webapps-manage", "allow": 1, "context": document },
|
||||
{ "type": "audio-channel-telephony", "allow": 1, "context": document }], runTest);
|
||||
},
|
||||
|
||||
// Preferences
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["media.useAudioChannelService", true],
|
||||
["media.defaultAudioChannel", "telephony"],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["network.disable.ipc.security", true]]}, runTest);
|
||||
},
|
||||
|
||||
// Run 2 apps
|
||||
mainApp,
|
||||
newApp,
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
function finish() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -20,6 +20,7 @@
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
|
||||
#include "BluetoothAdapter.h"
|
||||
#include "BluetoothClassOfDevice.h"
|
||||
#include "BluetoothDevice.h"
|
||||
#include "BluetoothDiscoveryHandle.h"
|
||||
#include "BluetoothReplyRunnable.h"
|
||||
@ -64,20 +65,23 @@ class StartDiscoveryTask : public BluetoothReplyRunnable
|
||||
NS_LITERAL_STRING("StartDiscovery"))
|
||||
, mAdapter(aAdapter)
|
||||
{
|
||||
MOZ_ASSERT(aPromise && aAdapter);
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_ASSERT(aAdapter);
|
||||
}
|
||||
|
||||
bool
|
||||
ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
BT_API2_LOGR();
|
||||
aValue.setUndefined();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
NS_ENSURE_TRUE(jsapi.Init(mAdapter->GetParentObject()), false);
|
||||
|
||||
// Wrap BluetoothDiscoveryHandle to return
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
/**
|
||||
* Create a new discovery handle and wrap it to return. Each
|
||||
* discovery handle is one-time-use only.
|
||||
*/
|
||||
nsRefPtr<BluetoothDiscoveryHandle> discoveryHandle =
|
||||
BluetoothDiscoveryHandle::Create(mAdapter->GetParentObject());
|
||||
if (!ToJSValue(cx, discoveryHandle, aValue)) {
|
||||
@ -85,6 +89,8 @@ class StartDiscoveryTask : public BluetoothReplyRunnable
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the created discovery handle as the one in use.
|
||||
mAdapter->SetDiscoveryHandleInUse(discoveryHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -205,6 +211,7 @@ BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
, mJsUuids(nullptr)
|
||||
, mJsDeviceAddresses(nullptr)
|
||||
, mDiscoveryHandleInUse(nullptr)
|
||||
, mState(BluetoothAdapterState::Disabled)
|
||||
, mDiscoverable(false)
|
||||
, mDiscovering(false)
|
||||
@ -273,9 +280,8 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
||||
const nsString& name = aValue.name();
|
||||
const BluetoothValue& value = aValue.value();
|
||||
if (name.EqualsLiteral("State")) {
|
||||
bool isEnabled = value.get_bool();
|
||||
mState = isEnabled ? BluetoothAdapterState::Enabled
|
||||
: BluetoothAdapterState::Disabled;
|
||||
mState = value.get_bool() ? BluetoothAdapterState::Enabled
|
||||
: BluetoothAdapterState::Disabled;
|
||||
} else if (name.EqualsLiteral("Name")) {
|
||||
mName = value.get_nsString();
|
||||
} else if (name.EqualsLiteral("Address")) {
|
||||
@ -284,6 +290,10 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
||||
mDiscoverable = value.get_bool();
|
||||
} else if (name.EqualsLiteral("Discovering")) {
|
||||
mDiscovering = value.get_bool();
|
||||
if (!mDiscovering) {
|
||||
// Reset discovery handle in use to nullptr
|
||||
SetDiscoveryHandleInUse(nullptr);
|
||||
}
|
||||
} else if (name.EqualsLiteral("Pairable")) {
|
||||
mPairable = value.get_bool();
|
||||
} else if (name.EqualsLiteral("Powered")) {
|
||||
@ -390,6 +400,18 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAdapter::SetDiscoveryHandleInUse(
|
||||
BluetoothDiscoveryHandle* aDiscoveryHandle)
|
||||
{
|
||||
// Stop discovery handle in use from listening to "DeviceFound" signal
|
||||
if (mDiscoveryHandleInUse) {
|
||||
mDiscoveryHandleInUse->DisconnectFromOwner();
|
||||
}
|
||||
|
||||
mDiscoveryHandleInUse = aDiscoveryHandle;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
BluetoothAdapter::StartStopDiscovery(bool aStart, ErrorResult& aRv)
|
||||
{
|
||||
@ -403,10 +425,13 @@ BluetoothAdapter::StartStopDiscovery(bool aStart, ErrorResult& aRv)
|
||||
/**
|
||||
* Ensure
|
||||
* - adapter does not already start/stop discovering,
|
||||
* (note we reject here to ensure each resolved promise of startDiscovery
|
||||
* returns a BluetoothDiscoveryHandle)
|
||||
* - adapter is already enabled, and
|
||||
* - BluetoothService is available
|
||||
*/
|
||||
BT_ENSURE_TRUE_RESOLVE(mDiscovering != aStart, JS::UndefinedHandleValue);
|
||||
BT_ENSURE_TRUE_REJECT(mDiscovering != aStart,
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled,
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
@ -824,12 +849,10 @@ BluetoothAdapter::IsAdapterAttributeChanged(BluetoothAdapterAttribute aType,
|
||||
const BluetoothValue& aValue)
|
||||
{
|
||||
switch(aType) {
|
||||
case BluetoothAdapterAttribute::State: {
|
||||
case BluetoothAdapterAttribute::State:
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::Tbool);
|
||||
bool isEnabled = aValue.get_bool();
|
||||
return isEnabled ? mState != BluetoothAdapterState::Enabled
|
||||
: mState != BluetoothAdapterState::Disabled;
|
||||
}
|
||||
return aValue.get_bool() ? mState != BluetoothAdapterState::Enabled
|
||||
: mState != BluetoothAdapterState::Disabled;
|
||||
case BluetoothAdapterAttribute::Name:
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TnsString);
|
||||
return !mName.Equals(aValue.get_nsString());
|
||||
@ -928,7 +951,7 @@ BluetoothAdapter::Connect(BluetoothDevice& aDevice,
|
||||
|
||||
nsAutoString address;
|
||||
aDevice.GetAddress(address);
|
||||
uint32_t deviceClass = aDevice.Class();
|
||||
uint32_t deviceClass = aDevice.Cod()->ToUint32();
|
||||
uint16_t serviceUuid = 0;
|
||||
if (aServiceUuid.WasPassed()) {
|
||||
serviceUuid = aServiceUuid.Value();
|
||||
|
@ -25,6 +25,7 @@ struct MediaPlayStatus;
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothDevice;
|
||||
class BluetoothDiscoveryHandle;
|
||||
class BluetoothSignal;
|
||||
class BluetoothNamedValue;
|
||||
class BluetoothValue;
|
||||
@ -93,6 +94,17 @@ public:
|
||||
void GetUuids(JSContext* aContext, JS::MutableHandle<JS::Value> aUuids,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Update this adapter's discovery handle in use (mDiscoveryHandleInUse).
|
||||
*
|
||||
* |mDiscoveryHandleInUse| is set to the latest discovery handle when adapter
|
||||
* just starts discovery, and is reset to nullptr when discovery is stopped
|
||||
* by some adapter.
|
||||
*
|
||||
* @param aDiscoveryHandle [in] the discovery handle to set.
|
||||
*/
|
||||
void SetDiscoveryHandleInUse(BluetoothDiscoveryHandle* aDiscoveryHandle);
|
||||
|
||||
already_AddRefed<Promise> SetName(const nsAString& aName, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
SetDiscoverable(bool aDiscoverable, ErrorResult& aRv);
|
||||
@ -189,6 +201,7 @@ private:
|
||||
|
||||
JS::Heap<JSObject*> mJsUuids;
|
||||
JS::Heap<JSObject*> mJsDeviceAddresses;
|
||||
nsRefPtr<BluetoothDiscoveryHandle> mDiscoveryHandleInUse;
|
||||
BluetoothAdapterState mState;
|
||||
nsString mAddress;
|
||||
nsString mName;
|
||||
|
@ -4,57 +4,82 @@
|
||||
* 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 "base/basictypes.h"
|
||||
#include "BluetoothClassOfDevice.h"
|
||||
#include "BluetoothDevice.h"
|
||||
#include "BluetoothReplyRunnable.h"
|
||||
#include "BluetoothService.h"
|
||||
#include "BluetoothUtils.h"
|
||||
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsTArrayHelpers.h"
|
||||
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
#include "mozilla/dom/BluetoothAttributeEvent.h"
|
||||
#include "mozilla/dom/BluetoothDevice2Binding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
DOMCI_DATA(BluetoothDevice, BluetoothDevice)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDevice)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothDevice,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsServices)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice,
|
||||
DOMEventTargetHelper)
|
||||
tmp->Unroot();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(BluetoothDevice, DOMEventTargetHelper, mCod)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(BluetoothDevice, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(BluetoothDevice, DOMEventTargetHelper)
|
||||
|
||||
class FetchUuidsTask : public BluetoothReplyRunnable
|
||||
{
|
||||
public:
|
||||
FetchUuidsTask(Promise* aPromise,
|
||||
const nsAString& aName,
|
||||
BluetoothDevice* aDevice)
|
||||
: BluetoothReplyRunnable(nullptr /* DOMRequest */, aPromise, aName)
|
||||
, mDevice(aDevice)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_ASSERT(aDevice);
|
||||
}
|
||||
|
||||
bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
aValue.setUndefined();
|
||||
|
||||
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
|
||||
NS_ENSURE_TRUE(v.type() == BluetoothValue::TArrayOfnsString, false);
|
||||
const InfallibleTArray<nsString>& uuids = v.get_ArrayOfnsString();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
NS_ENSURE_TRUE(jsapi.Init(mDevice->GetParentObject()), false);
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
if (!ToJSValue(cx, uuids, aValue)) {
|
||||
BT_WARNING("Cannot create JS array!");
|
||||
JS_ClearPendingException(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void ReleaseMembers() MOZ_OVERRIDE
|
||||
{
|
||||
BluetoothReplyRunnable::ReleaseMembers();
|
||||
mDevice = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothDevice> mDevice;
|
||||
};
|
||||
|
||||
BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aWindow,
|
||||
const BluetoothValue& aValue)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
, mJsUuids(nullptr)
|
||||
, mJsServices(nullptr)
|
||||
, mIsRooted(false)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(IsDOMBinding());
|
||||
|
||||
mCod = BluetoothClassOfDevice::Create(aWindow);
|
||||
|
||||
const InfallibleTArray<BluetoothNamedValue>& values =
|
||||
aValue.get_ArrayOfBluetoothNamedValue();
|
||||
for (uint32_t i = 0; i < values.Length(); ++i) {
|
||||
@ -72,7 +97,6 @@ BluetoothDevice::~BluetoothDevice()
|
||||
// bs can be null on shutdown, where destruction might happen.
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
bs->UnregisterBluetoothSignalHandler(mAddress, this);
|
||||
Unroot();
|
||||
}
|
||||
|
||||
void
|
||||
@ -85,26 +109,6 @@ BluetoothDevice::DisconnectFromOwner()
|
||||
bs->UnregisterBluetoothSignalHandler(mAddress, this);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDevice::Root()
|
||||
{
|
||||
if (!mIsRooted) {
|
||||
mozilla::HoldJSObjects(this);
|
||||
mIsRooted = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDevice::Unroot()
|
||||
{
|
||||
if (mIsRooted) {
|
||||
mJsUuids = nullptr;
|
||||
mJsServices = nullptr;
|
||||
mozilla::DropJSObjects(this);
|
||||
mIsRooted = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
||||
{
|
||||
@ -114,54 +118,47 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
||||
mName = value.get_nsString();
|
||||
} else if (name.EqualsLiteral("Address")) {
|
||||
mAddress = value.get_nsString();
|
||||
} else if (name.EqualsLiteral("Class")) {
|
||||
mClass = value.get_uint32_t();
|
||||
} else if (name.EqualsLiteral("Icon")) {
|
||||
mIcon = value.get_nsString();
|
||||
} else if (name.EqualsLiteral("Connected")) {
|
||||
mConnected = value.get_bool();
|
||||
} else if (name.EqualsLiteral("Cod")) {
|
||||
mCod->Update(value.get_uint32_t());
|
||||
} else if (name.EqualsLiteral("Paired")) {
|
||||
mPaired = value.get_bool();
|
||||
} else if (name.EqualsLiteral("UUIDs")) {
|
||||
// We assume the received uuids array is sorted without duplicate items.
|
||||
// If it's not, we require additional processing before assigning it
|
||||
// directly.
|
||||
mUuids = value.get_ArrayOfnsString();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(GetOwner())) {
|
||||
BT_WARNING("Failed to initialise AutoJSAPI!");
|
||||
return;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> uuids(cx);
|
||||
if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, &uuids))) {
|
||||
BT_WARNING("Cannot set JS UUIDs object!");
|
||||
return;
|
||||
}
|
||||
mJsUuids = uuids;
|
||||
Root();
|
||||
} else if (name.EqualsLiteral("Services")) {
|
||||
mServices = value.get_ArrayOfnsString();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(GetOwner())) {
|
||||
BT_WARNING("Failed to initialise AutoJSAPI!");
|
||||
return;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> services(cx);
|
||||
if (NS_FAILED(nsTArrayToJSArray(cx, mServices, &services))) {
|
||||
BT_WARNING("Cannot set JS Services object!");
|
||||
return;
|
||||
}
|
||||
mJsServices = services;
|
||||
Root();
|
||||
BluetoothDeviceBinding::ClearCachedUuidsValue(this);
|
||||
} else {
|
||||
nsCString warningMsg;
|
||||
warningMsg.AssignLiteral("Not handling device property: ");
|
||||
warningMsg.Append(NS_ConvertUTF16toUTF8(name));
|
||||
BT_WARNING(warningMsg.get());
|
||||
BT_WARNING("Not handling device property: %s",
|
||||
NS_ConvertUTF16toUTF8(name).get());
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
BluetoothDevice::FetchUuids(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = new Promise(global);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsRefPtr<BluetoothReplyRunnable> result =
|
||||
new FetchUuidsTask(promise,
|
||||
NS_LITERAL_STRING("FetchUuids"),
|
||||
this);
|
||||
|
||||
nsresult rv = bs->FetchUuidsInternal(mAddress, result);
|
||||
BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(rv), NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<BluetoothDevice>
|
||||
BluetoothDevice::Create(nsPIDOMWindow* aWindow,
|
||||
@ -177,56 +174,112 @@ BluetoothDevice::Create(nsPIDOMWindow* aWindow,
|
||||
void
|
||||
BluetoothDevice::Notify(const BluetoothSignal& aData)
|
||||
{
|
||||
BT_LOGD("[D] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||
BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||
|
||||
BluetoothValue v = aData.value();
|
||||
if (aData.name().EqualsLiteral("PropertyChanged")) {
|
||||
MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
|
||||
|
||||
const InfallibleTArray<BluetoothNamedValue>& arr =
|
||||
v.get_ArrayOfBluetoothNamedValue();
|
||||
|
||||
for (uint32_t i = 0, propCount = arr.Length(); i < propCount; ++i) {
|
||||
SetPropertyByValue(arr[i]);
|
||||
}
|
||||
HandlePropertyChanged(v);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
nsCString warningMsg;
|
||||
warningMsg.AssignLiteral("Not handling device signal: ");
|
||||
warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
|
||||
BT_WARNING(warningMsg.get());
|
||||
#endif
|
||||
BT_WARNING("Not handling device signal: %s",
|
||||
NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||
}
|
||||
}
|
||||
|
||||
BluetoothDeviceAttribute
|
||||
BluetoothDevice::ConvertStringToDeviceAttribute(const nsAString& aString)
|
||||
{
|
||||
using namespace
|
||||
mozilla::dom::BluetoothDeviceAttributeValues;
|
||||
|
||||
for (size_t index = 0; index < ArrayLength(strings) - 1; index++) {
|
||||
if (aString.LowerCaseEqualsASCII(strings[index].value,
|
||||
strings[index].length)) {
|
||||
return static_cast<BluetoothDeviceAttribute>(index);
|
||||
}
|
||||
}
|
||||
|
||||
return BluetoothDeviceAttribute::Unknown;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothDevice::IsDeviceAttributeChanged(BluetoothDeviceAttribute aType,
|
||||
const BluetoothValue& aValue)
|
||||
{
|
||||
switch (aType) {
|
||||
case BluetoothDeviceAttribute::Cod:
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::Tuint32_t);
|
||||
return !mCod->Equals(aValue.get_uint32_t());
|
||||
case BluetoothDeviceAttribute::Name:
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TnsString);
|
||||
return !mName.Equals(aValue.get_nsString());
|
||||
case BluetoothDeviceAttribute::Paired:
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::Tbool);
|
||||
return mPaired != aValue.get_bool();
|
||||
case BluetoothDeviceAttribute::Uuids: {
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfnsString);
|
||||
const InfallibleTArray<nsString>& uuids = aValue.get_ArrayOfnsString();
|
||||
// We assume the received uuids array is sorted without duplicate items.
|
||||
// If it's not, we require additional processing before comparing it
|
||||
// directly.
|
||||
return mUuids != uuids;
|
||||
}
|
||||
default:
|
||||
BT_WARNING("Type %d is not handled", uint32_t(aType));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDevice::GetUuids(JSContext* aContext,
|
||||
JS::MutableHandle<JS::Value> aUuids,
|
||||
ErrorResult& aRv)
|
||||
BluetoothDevice::HandlePropertyChanged(const BluetoothValue& aValue)
|
||||
{
|
||||
if (!mJsUuids) {
|
||||
BT_WARNING("UUIDs not yet set!");
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
|
||||
|
||||
const InfallibleTArray<BluetoothNamedValue>& arr =
|
||||
aValue.get_ArrayOfBluetoothNamedValue();
|
||||
|
||||
nsTArray<nsString> types;
|
||||
for (uint32_t i = 0, propCount = arr.Length(); i < propCount; ++i) {
|
||||
BluetoothDeviceAttribute type =
|
||||
ConvertStringToDeviceAttribute(arr[i].name());
|
||||
|
||||
// Non-BluetoothDeviceAttribute properties
|
||||
if (type == BluetoothDeviceAttribute::Unknown) {
|
||||
SetPropertyByValue(arr[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// BluetoothDeviceAttribute properties
|
||||
if (IsDeviceAttributeChanged(type, arr[i].value())) {
|
||||
SetPropertyByValue(arr[i]);
|
||||
BT_APPEND_ENUM_STRING(types, BluetoothDeviceAttribute, type);
|
||||
}
|
||||
}
|
||||
|
||||
JS::ExposeObjectToActiveJS(mJsUuids);
|
||||
aUuids.setObject(*mJsUuids);
|
||||
DispatchAttributeEvent(types);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDevice::GetServices(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aServices,
|
||||
ErrorResult& aRv)
|
||||
BluetoothDevice::DispatchAttributeEvent(const nsTArray<nsString>& aTypes)
|
||||
{
|
||||
if (!mJsServices) {
|
||||
BT_WARNING("Services not yet set!");
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE_VOID(aTypes.Length());
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
NS_ENSURE_TRUE_VOID(jsapi.Init(GetOwner()));
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JS::Value> value(cx);
|
||||
|
||||
if (!ToJSValue(cx, aTypes, &value)) {
|
||||
JS_ClearPendingException(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::ExposeObjectToActiveJS(mJsServices);
|
||||
aServices.setObject(*mJsServices);
|
||||
RootedDictionary<BluetoothAttributeEventInit> init(cx);
|
||||
init.mAttrs = value;
|
||||
nsRefPtr<BluetoothAttributeEvent> event =
|
||||
BluetoothAttributeEvent::Constructor(this,
|
||||
NS_LITERAL_STRING("attributechanged"),
|
||||
init);
|
||||
DispatchTrustedEvent(event);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -9,24 +9,33 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/BluetoothDevice2Binding.h"
|
||||
#include "BluetoothCommon.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Promise;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothClassOfDevice;
|
||||
class BluetoothNamedValue;
|
||||
class BluetoothValue;
|
||||
class BluetoothSignal;
|
||||
class BluetoothSocket;
|
||||
|
||||
class BluetoothDevice : public DOMEventTargetHelper
|
||||
, public BluetoothSignalObserver
|
||||
class BluetoothDevice MOZ_FINAL : public DOMEventTargetHelper
|
||||
, public BluetoothSignalObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(BluetoothDevice,
|
||||
DOMEventTargetHelper)
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothDevice,
|
||||
DOMEventTargetHelper)
|
||||
|
||||
static already_AddRefed<BluetoothDevice>
|
||||
Create(nsPIDOMWindow* aOwner, const BluetoothValue& aValue);
|
||||
@ -38,73 +47,59 @@ public:
|
||||
aAddress = mAddress;
|
||||
}
|
||||
|
||||
BluetoothClassOfDevice* Cod() const
|
||||
{
|
||||
return mCod;
|
||||
}
|
||||
|
||||
void GetName(nsString& aName) const
|
||||
{
|
||||
aName = mName;
|
||||
}
|
||||
|
||||
void GetIcon(nsString& aIcon) const
|
||||
{
|
||||
aIcon = mIcon;
|
||||
}
|
||||
|
||||
uint32_t Class() const
|
||||
{
|
||||
return mClass;
|
||||
}
|
||||
|
||||
bool Paired() const
|
||||
{
|
||||
return mPaired;
|
||||
}
|
||||
|
||||
bool Connected() const
|
||||
{
|
||||
return mConnected;
|
||||
void GetUuids(nsTArray<nsString>& aUuids) {
|
||||
aUuids = mUuids;
|
||||
}
|
||||
|
||||
void GetUuids(JSContext* aContext, JS::MutableHandle<JS::Value> aUuids,
|
||||
ErrorResult& aRv);
|
||||
void GetServices(JSContext* aContext, JS::MutableHandle<JS::Value> aServices,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsISupports*
|
||||
ToISupports()
|
||||
{
|
||||
return static_cast<EventTarget*>(this);
|
||||
}
|
||||
already_AddRefed<Promise> FetchUuids(ErrorResult& aRv);
|
||||
|
||||
void SetPropertyByValue(const BluetoothNamedValue& aValue);
|
||||
|
||||
void Unroot();
|
||||
BluetoothDeviceAttribute
|
||||
ConvertStringToDeviceAttribute(const nsAString& aString);
|
||||
|
||||
bool
|
||||
IsDeviceAttributeChanged(BluetoothDeviceAttribute aType,
|
||||
const BluetoothValue& aValue);
|
||||
|
||||
void HandlePropertyChanged(const BluetoothValue& aValue);
|
||||
|
||||
void DispatchAttributeEvent(const nsTArray<nsString>& aTypes);
|
||||
|
||||
IMPL_EVENT_HANDLER(attributechanged);
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
virtual void DisconnectFromOwner() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
BluetoothDevice(nsPIDOMWindow* aOwner, const BluetoothValue& aValue);
|
||||
~BluetoothDevice();
|
||||
void Root();
|
||||
|
||||
JS::Heap<JSObject*> mJsUuids;
|
||||
JS::Heap<JSObject*> mJsServices;
|
||||
|
||||
nsString mAddress;
|
||||
nsRefPtr<BluetoothClassOfDevice> mCod;
|
||||
nsString mName;
|
||||
nsString mIcon;
|
||||
uint32_t mClass;
|
||||
bool mConnected;
|
||||
bool mPaired;
|
||||
bool mIsRooted;
|
||||
nsTArray<nsString> mUuids;
|
||||
nsTArray<nsString> mServices;
|
||||
|
||||
};
|
||||
|
||||
|
@ -91,6 +91,13 @@ BluetoothDiscoveryHandle::Notify(const BluetoothSignal& aData)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDiscoveryHandle::DisconnectFromOwner()
|
||||
{
|
||||
DOMEventTargetHelper::DisconnectFromOwner();
|
||||
ListenToBluetoothSignal(false);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothDiscoveryHandle::WrapObject(JSContext* aCx)
|
||||
{
|
||||
|
@ -30,6 +30,8 @@ public:
|
||||
IMPL_EVENT_HANDLER(devicefound);
|
||||
|
||||
void Notify(const BluetoothSignal& aData); // BluetoothSignalObserver
|
||||
|
||||
virtual void DisconnectFromOwner() MOZ_OVERRIDE;
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
@ -151,6 +151,16 @@ public:
|
||||
GetConnectedDevicePropertiesInternal(uint16_t aServiceUuid,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Returns up-to-date uuids of given device address,
|
||||
* implemented via a platform specific methood.
|
||||
*
|
||||
* @return NS_OK on success, NS_ERROR_FAILURE otherwise
|
||||
*/
|
||||
virtual nsresult
|
||||
FetchUuidsInternal(const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Stop device discovery (platform specific implementation)
|
||||
*
|
||||
|
@ -63,6 +63,7 @@ static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeAdapterStateRunnableAr
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sFetchUuidsRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
|
||||
|
||||
@ -123,10 +124,11 @@ public:
|
||||
|
||||
// Bluetooth just enabled, clear profile controllers and runnable arrays.
|
||||
sControllerArray.Clear();
|
||||
sBondingRunnableArray.Clear();
|
||||
sChangeDiscoveryRunnableArray.Clear();
|
||||
sGetDeviceRunnableArray.Clear();
|
||||
sSetPropertyRunnableArray.Clear();
|
||||
sGetDeviceRunnableArray.Clear();
|
||||
sFetchUuidsRunnableArray.Clear();
|
||||
sBondingRunnableArray.Clear();
|
||||
sUnbondingRunnableArray.Clear();
|
||||
|
||||
// Bluetooth scan mode is NONE by default
|
||||
@ -194,97 +196,6 @@ public:
|
||||
/**
|
||||
* Static callback functions
|
||||
*/
|
||||
static void
|
||||
ClassToIcon(uint32_t aClass, nsAString& aRetIcon)
|
||||
{
|
||||
switch ((aClass & 0x1f00) >> 8) {
|
||||
case 0x01:
|
||||
aRetIcon.AssignLiteral("computer");
|
||||
break;
|
||||
case 0x02:
|
||||
switch ((aClass & 0xfc) >> 2) {
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x05:
|
||||
aRetIcon.AssignLiteral("phone");
|
||||
break;
|
||||
case 0x04:
|
||||
aRetIcon.AssignLiteral("modem");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x03:
|
||||
aRetIcon.AssignLiteral("network-wireless");
|
||||
break;
|
||||
case 0x04:
|
||||
switch ((aClass & 0xfc) >> 2) {
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x06:
|
||||
aRetIcon.AssignLiteral("audio-card");
|
||||
break;
|
||||
case 0x0b:
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
aRetIcon.AssignLiteral("camera-video");
|
||||
break;
|
||||
default:
|
||||
aRetIcon.AssignLiteral("audio-card");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x05:
|
||||
switch ((aClass & 0xc0) >> 6) {
|
||||
case 0x00:
|
||||
switch ((aClass && 0x1e) >> 2) {
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
aRetIcon.AssignLiteral("input-gaming");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
aRetIcon.AssignLiteral("input-keyboard");
|
||||
break;
|
||||
case 0x02:
|
||||
switch ((aClass && 0x1e) >> 2) {
|
||||
case 0x05:
|
||||
aRetIcon.AssignLiteral("input-tablet");
|
||||
break;
|
||||
default:
|
||||
aRetIcon.AssignLiteral("input-mouse");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
if (aClass & 0x80) {
|
||||
aRetIcon.AssignLiteral("printer");
|
||||
break;
|
||||
}
|
||||
if (aClass & 0x20) {
|
||||
aRetIcon.AssignLiteral("camera-photo");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (aRetIcon.IsEmpty()) {
|
||||
if (HAS_AUDIO(aClass)) {
|
||||
/**
|
||||
* Property 'Icon' may be missed due to CoD of major class is TOY(0x08).
|
||||
* But we need to assign Icon as audio-card if service class is 'Audio'.
|
||||
* This is for PTS test case TC_AG_COD_BV_02_I. As HFP specification
|
||||
* defines that service class is 'Audio' can be considered as HFP HF.
|
||||
*/
|
||||
aRetIcon.AssignLiteral("audio-card");
|
||||
} else {
|
||||
BT_LOGR("No icon to match class: %x", aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ControlPlayStatus
|
||||
PlayStatusStringToControlPlayStatus(const nsAString& aPlayStatus)
|
||||
{
|
||||
@ -476,11 +387,6 @@ public:
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sRequestedDeviceCountArray.IsEmpty()) {
|
||||
// This is possible because the callback would be called after turning
|
||||
// Bluetooth on.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Update to registered BluetoothDevice objects
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
|
||||
@ -492,6 +398,24 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// FetchUuids task
|
||||
if (!sFetchUuidsRunnableArray.IsEmpty()) {
|
||||
// mProps contains Address and Uuids only
|
||||
DispatchBluetoothReply(sFetchUuidsRunnableArray[0],
|
||||
mProps[1].value() /* Uuids */,
|
||||
EmptyString());
|
||||
sFetchUuidsRunnableArray.RemoveElementAt(0);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// GetDevices task
|
||||
if (sRequestedDeviceCountArray.IsEmpty()) {
|
||||
// This is possible because the callback would be called after turning
|
||||
// Bluetooth on.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Use address as the index
|
||||
sRemoteDevicesPack.AppendElement(
|
||||
BluetoothNamedValue(mRemoteDeviceBdAddress, mProps));
|
||||
@ -515,6 +439,7 @@ public:
|
||||
* RemoteDevicePropertiesCallback will be called, as the following conditions:
|
||||
* 1. When BT is turning on, bluedroid automatically execute this callback
|
||||
* 2. When get_remote_device_properties()
|
||||
* 3. When get_remote_services()
|
||||
*/
|
||||
static void
|
||||
RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress,
|
||||
@ -536,11 +461,22 @@ RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress,
|
||||
BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
|
||||
uint32_t cod = *(uint32_t*)p.val;
|
||||
BT_APPEND_NAMED_VALUE(props, "Class", cod);
|
||||
BT_APPEND_NAMED_VALUE(props, "Cod", cod);
|
||||
} else if (p.type == BT_PROPERTY_UUIDS) {
|
||||
nsTArray<nsString> uuids;
|
||||
|
||||
nsString icon;
|
||||
ClassToIcon(cod, icon);
|
||||
BT_APPEND_NAMED_VALUE(props, "Icon", icon);
|
||||
// Construct a sorted uuid set
|
||||
for (uint32_t j = 0; j < p.len / sizeof(bt_uuid_t); j++) {
|
||||
nsAutoString uuid;
|
||||
bt_uuid_t* pUuid = (bt_uuid_t*)p.val + j;
|
||||
UuidToString(pUuid, uuid);
|
||||
|
||||
if (!uuids.Contains(uuid)) { // filter out duplicate uuids
|
||||
uuids.InsertElementSorted(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
BT_APPEND_NAMED_VALUE(props, "UUIDs", uuids);
|
||||
} else {
|
||||
BT_LOGD("Other non-handled device properties. Type: %d", p.type);
|
||||
}
|
||||
@ -574,12 +510,7 @@ DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties)
|
||||
} else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
|
||||
uint32_t cod = *(uint32_t*)p.val;
|
||||
propertyValue = cod;
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Class", propertyValue);
|
||||
|
||||
nsString icon;
|
||||
ClassToIcon(cod, icon);
|
||||
propertyValue = icon;
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Icon", propertyValue);
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Cod", cod);
|
||||
} else {
|
||||
BT_LOGD("Not handled remote device property: %d", p.type);
|
||||
}
|
||||
@ -1251,6 +1182,51 @@ BluetoothServiceBluedroid::StopDiscoveryInternal(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class GetRemoteServicesResultHandler MOZ_FINAL : public BluetoothResultHandler
|
||||
{
|
||||
public:
|
||||
GetRemoteServicesResultHandler(BluetoothReplyRunnable* aRunnable)
|
||||
: mRunnable(aRunnable)
|
||||
{ }
|
||||
|
||||
void OnError(int aStatus) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
sFetchUuidsRunnableArray.RemoveElement(mRunnable);
|
||||
ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("FetchUuids"));
|
||||
}
|
||||
|
||||
private:
|
||||
BluetoothReplyRunnable* mRunnable;
|
||||
};
|
||||
|
||||
nsresult
|
||||
BluetoothServiceBluedroid::FetchUuidsInternal(
|
||||
const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
|
||||
|
||||
/*
|
||||
* get_remote_services request will not be performed by bluedroid
|
||||
* if it is currently discovering nearby remote devices.
|
||||
*/
|
||||
if (sAdapterDiscovering) {
|
||||
sBtInterface->CancelDiscovery(new CancelDiscoveryResultHandler(aRunnable));
|
||||
}
|
||||
|
||||
bt_bdaddr_t addressType;
|
||||
StringToBdAddressType(aDeviceAddress, &addressType);
|
||||
|
||||
sFetchUuidsRunnableArray.AppendElement(aRunnable);
|
||||
|
||||
sBtInterface->GetRemoteServices(&addressType,
|
||||
new GetRemoteServicesResultHandler(aRunnable));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class SetAdapterPropertyResultHandler MOZ_FINAL : public BluetoothResultHandler
|
||||
{
|
||||
public:
|
||||
@ -1766,4 +1742,3 @@ void
|
||||
BluetoothServiceBluedroid::ToggleCalls(BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,10 @@ public:
|
||||
GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual nsresult
|
||||
FetchUuidsInternal(const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult StartDiscoveryInternal(BluetoothReplyRunnable* aRunnable);
|
||||
virtual nsresult StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
|
@ -49,6 +49,29 @@ BdAddressTypeToString(bt_bdaddr_t* aBdAddressType, nsAString& aRetBdAddress)
|
||||
aRetBdAddress = NS_ConvertUTF8toUTF16(bdstr);
|
||||
}
|
||||
|
||||
void
|
||||
UuidToString(bt_uuid_t* aUuid, nsAString& aString) {
|
||||
char uuidStr[37];
|
||||
|
||||
uint32_t uuid0, uuid4;
|
||||
uint16_t uuid1, uuid2, uuid3, uuid5;
|
||||
|
||||
memcpy(&uuid0, &(aUuid->uu[0]), sizeof(uint32_t));
|
||||
memcpy(&uuid1, &(aUuid->uu[4]), sizeof(uint16_t));
|
||||
memcpy(&uuid2, &(aUuid->uu[6]), sizeof(uint16_t));
|
||||
memcpy(&uuid3, &(aUuid->uu[8]), sizeof(uint16_t));
|
||||
memcpy(&uuid4, &(aUuid->uu[10]), sizeof(uint32_t));
|
||||
memcpy(&uuid5, &(aUuid->uu[14]), sizeof(uint16_t));
|
||||
|
||||
sprintf(uuidStr, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
|
||||
ntohl(uuid0), ntohs(uuid1),
|
||||
ntohs(uuid2), ntohs(uuid3),
|
||||
ntohl(uuid4), ntohs(uuid5));
|
||||
|
||||
aString.Truncate();
|
||||
aString.AssignLiteral(uuidStr);
|
||||
}
|
||||
|
||||
bool
|
||||
SetJsObject(JSContext* aContext,
|
||||
const BluetoothValue& aValue,
|
||||
|
@ -26,6 +26,9 @@ void
|
||||
BdAddressTypeToString(bt_bdaddr_t* aBdAddressType,
|
||||
nsAString& aRetBdAddress);
|
||||
|
||||
void
|
||||
UuidToString(bt_uuid_t* aUuid, nsAString& aString);
|
||||
|
||||
bool
|
||||
SetJsObject(JSContext* aContext,
|
||||
const BluetoothValue& aValue,
|
||||
|
@ -2814,6 +2814,13 @@ BluetoothDBusService::GetPairedDevicePropertiesInternal(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FetchUuidsInternal(const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class SetPropertyTask : public Task
|
||||
{
|
||||
public:
|
||||
|
@ -62,6 +62,10 @@ public:
|
||||
GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
|
||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
FetchUuidsInternal(const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult StartDiscoveryInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
@ -210,6 +210,8 @@ BluetoothParent::RecvPBluetoothRequestConstructor(
|
||||
return actor->DoRequest(aRequest.get_PairedDevicePropertiesRequest());
|
||||
case Request::TConnectedDevicePropertiesRequest:
|
||||
return actor->DoRequest(aRequest.get_ConnectedDevicePropertiesRequest());
|
||||
case Request::TFetchUuidsRequest:
|
||||
return actor->DoRequest(aRequest.get_FetchUuidsRequest());
|
||||
case Request::TSetPinCodeRequest:
|
||||
return actor->DoRequest(aRequest.get_SetPinCodeRequest());
|
||||
case Request::TSetPasskeyRequest:
|
||||
@ -432,7 +434,8 @@ BluetoothRequestParent::DoRequest(const PairedDevicePropertiesRequest& aRequest)
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const ConnectedDevicePropertiesRequest& aRequest)
|
||||
BluetoothRequestParent::DoRequest(
|
||||
const ConnectedDevicePropertiesRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
MOZ_ASSERT(mRequestType == Request::TConnectedDevicePropertiesRequest);
|
||||
@ -444,6 +447,19 @@ BluetoothRequestParent::DoRequest(const ConnectedDevicePropertiesRequest& aReque
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const FetchUuidsRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
MOZ_ASSERT(mRequestType == Request::TFetchUuidsRequest);
|
||||
nsresult rv =
|
||||
mService->FetchUuidsInternal(aRequest.address(), mReplyRunnable.get());
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const SetPinCodeRequest& aRequest)
|
||||
{
|
||||
|
@ -154,9 +154,13 @@ protected:
|
||||
|
||||
bool
|
||||
DoRequest(const PairedDevicePropertiesRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const ConnectedDevicePropertiesRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const FetchUuidsRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const SetPinCodeRequest& aRequest);
|
||||
|
||||
|
@ -125,6 +125,7 @@ BluetoothServiceChildProcess::GetConnectedDevicePropertiesInternal(
|
||||
SendRequest(aRunnable, ConnectedDevicePropertiesRequest(aServiceUuid));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceChildProcess::GetPairedDevicePropertiesInternal(
|
||||
const nsTArray<nsString>& aDeviceAddresses,
|
||||
@ -137,6 +138,14 @@ BluetoothServiceChildProcess::GetPairedDevicePropertiesInternal(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceChildProcess::FetchUuidsInternal(
|
||||
const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
SendRequest(aRunnable, FetchUuidsRequest(nsString(aDeviceAddress)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceChildProcess::StopDiscoveryInternal(
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
|
@ -62,6 +62,10 @@ public:
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
MOZ_OVERRIDE;
|
||||
virtual nsresult
|
||||
FetchUuidsInternal(const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
|
@ -96,6 +96,11 @@ struct ConnectedDevicePropertiesRequest
|
||||
uint16_t serviceUuid;
|
||||
};
|
||||
|
||||
struct FetchUuidsRequest
|
||||
{
|
||||
nsString address;
|
||||
};
|
||||
|
||||
struct ConnectRequest
|
||||
{
|
||||
nsString address;
|
||||
@ -188,6 +193,7 @@ union Request
|
||||
DenyPairingConfirmationRequest;
|
||||
ConnectedDevicePropertiesRequest;
|
||||
PairedDevicePropertiesRequest;
|
||||
FetchUuidsRequest;
|
||||
ConnectRequest;
|
||||
DisconnectRequest;
|
||||
SendFileRequest;
|
||||
|
@ -22,6 +22,11 @@ StaticAutoPtr<nsCString> CameraPreferences::sPrefGonkParameters;
|
||||
nsresult CameraPreferences::sPrefCameraControlMethodErrorOverride = NS_OK;
|
||||
nsresult CameraPreferences::sPrefCameraControlAsyncErrorOverride = NS_OK;
|
||||
|
||||
uint32_t CameraPreferences::sPrefCameraControlLowMemoryThresholdMB = 0;
|
||||
|
||||
bool CameraPreferences::sPrefCameraParametersIsLowMemory = false;
|
||||
|
||||
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
|
||||
/* static */
|
||||
nsresult
|
||||
CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
|
||||
@ -33,6 +38,19 @@ CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
CameraPreferences::UpdatePref(const char* aPref, uint32_t& aVal)
|
||||
{
|
||||
uint32_t val;
|
||||
nsresult rv = Preferences::GetUint(aPref, &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aVal = val;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
@ -46,6 +64,18 @@ CameraPreferences::UpdatePref(const char* aPref, nsACString& aVal)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
CameraPreferences::UpdatePref(const char* aPref, bool& aVal)
|
||||
{
|
||||
bool val;
|
||||
nsresult rv = Preferences::GetBool(aPref, &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aVal = val;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
CameraPreferences::Pref CameraPreferences::sPrefs[] = {
|
||||
{
|
||||
@ -67,14 +97,24 @@ CameraPreferences::Pref CameraPreferences::sPrefs[] = {
|
||||
#endif
|
||||
{
|
||||
"camera.control.test.method.error",
|
||||
kPrefValueIsNSResult,
|
||||
kPrefValueIsNsResult,
|
||||
{ &sPrefCameraControlMethodErrorOverride }
|
||||
},
|
||||
{
|
||||
"camera.control.test.async.error",
|
||||
kPrefValueIsNSResult,
|
||||
kPrefValueIsNsResult,
|
||||
{ &sPrefCameraControlAsyncErrorOverride }
|
||||
},
|
||||
{
|
||||
"camera.control.test.is_low_memory",
|
||||
kPrefValueIsBoolean,
|
||||
{ &sPrefCameraParametersIsLowMemory }
|
||||
},
|
||||
{
|
||||
"camera.control.low_memory_thresholdMB",
|
||||
kPrefValueIsUint32,
|
||||
{ &sPrefCameraControlLowMemoryThresholdMB }
|
||||
},
|
||||
};
|
||||
|
||||
/* static */
|
||||
@ -104,7 +144,8 @@ CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
|
||||
Pref& p = sPrefs[i];
|
||||
nsresult rv;
|
||||
switch (p.mValueType) {
|
||||
case kPrefValueIsNSResult:
|
||||
case kPrefValueIsNsResult:
|
||||
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
|
||||
{
|
||||
nsresult& v = *p.mValue.mAsNsResult;
|
||||
rv = UpdatePref(aPref, v);
|
||||
@ -113,6 +154,17 @@ CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case kPrefValueIsUint32:
|
||||
{
|
||||
uint32_t& v = *p.mValue.mAsUint32;
|
||||
rv = UpdatePref(aPref, v);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DOM_CAMERA_LOGI("Preference '%s' has changed, %u\n", aPref, v);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kPrefValueIsCString:
|
||||
{
|
||||
@ -124,6 +176,17 @@ CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
|
||||
}
|
||||
break;
|
||||
|
||||
case kPrefValueIsBoolean:
|
||||
{
|
||||
bool& v = *p.mValue.mAsBoolean;
|
||||
rv = UpdatePref(aPref, v);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DOM_CAMERA_LOGI("Preference '%s' has changed, %s\n",
|
||||
aPref, v ? "true" : "false");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unhandled preference value type!");
|
||||
return;
|
||||
@ -211,6 +274,7 @@ CameraPreferences::GetPref(const char* aPref, nsACString& aVal)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
|
||||
/* static */
|
||||
bool
|
||||
CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
|
||||
@ -223,14 +287,14 @@ CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
|
||||
return false;
|
||||
}
|
||||
if (sPrefs[i].mValueType != kPrefValueIsNSResult) {
|
||||
if (sPrefs[i].mValueType != kPrefValueIsNsResult) {
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not an nsresult type\n", aPref);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult v = *sPrefs[i].mValue.mAsNsResult;
|
||||
if (v == NS_OK) {
|
||||
DOM_CAMERA_LOGI("Preference '%s' is not set\n", aPref);
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not set\n", aPref);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -238,3 +302,50 @@ CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
|
||||
aVal = v;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CameraPreferences::GetPref(const char* aPref, uint32_t& aVal)
|
||||
{
|
||||
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
|
||||
MonitorAutoLock mon(*sPrefMonitor);
|
||||
|
||||
uint32_t i = PrefToIndex(aPref);
|
||||
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
|
||||
return false;
|
||||
}
|
||||
if (sPrefs[i].mValueType != kPrefValueIsUint32) {
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not a uint32_t type\n", aPref);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t v = *sPrefs[i].mValue.mAsUint32;
|
||||
DOM_CAMERA_LOGI("Preference '%s', got %u\n", aPref, v);
|
||||
aVal = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CameraPreferences::GetPref(const char* aPref, bool& aVal)
|
||||
{
|
||||
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
|
||||
MonitorAutoLock mon(*sPrefMonitor);
|
||||
|
||||
uint32_t i = PrefToIndex(aPref);
|
||||
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
|
||||
return false;
|
||||
}
|
||||
if (sPrefs[i].mValueType != kPrefValueIsBoolean) {
|
||||
DOM_CAMERA_LOGW("Preference '%s' is not a boolean type\n", aPref);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool v = *sPrefs[i].mValue.mAsBoolean;
|
||||
DOM_CAMERA_LOGI("Preference '%s', got %s\n", aPref, v ? "true" : "false");
|
||||
aVal = v;
|
||||
return true;
|
||||
}
|
||||
|
@ -8,6 +8,13 @@
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
#if defined(MOZ_HAVE_CXX11_STRONG_ENUMS) || defined(MOZ_HAVE_CXX11_ENUM_TYPE)
|
||||
// Older compilers that don't support strongly-typed enums
|
||||
// just typedef uint32_t to nsresult, which results in conflicting
|
||||
// overloaded members in CameraPreferences.
|
||||
#define CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<class T> class StaticAutoPtr;
|
||||
@ -19,19 +26,29 @@ public:
|
||||
static void Shutdown();
|
||||
|
||||
static bool GetPref(const char* aPref, nsACString& aVal);
|
||||
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
|
||||
static bool GetPref(const char* aPref, nsresult& aVal);
|
||||
#endif
|
||||
static bool GetPref(const char* aPref, uint32_t& aVal);
|
||||
static bool GetPref(const char* aPref, bool& aVal);
|
||||
|
||||
protected:
|
||||
static const uint32_t kPrefNotFound = UINT32_MAX;
|
||||
static uint32_t PrefToIndex(const char* aPref);
|
||||
|
||||
static void PreferenceChanged(const char* aPref, void* aClosure);
|
||||
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
|
||||
static nsresult UpdatePref(const char* aPref, nsresult& aVar);
|
||||
#endif
|
||||
static nsresult UpdatePref(const char* aPref, uint32_t& aVar);
|
||||
static nsresult UpdatePref(const char* aPref, nsACString& aVar);
|
||||
static nsresult UpdatePref(const char* aPref, bool& aVar);
|
||||
|
||||
enum PrefValueType {
|
||||
kPrefValueIsNSResult,
|
||||
kPrefValueIsCString
|
||||
kPrefValueIsNsResult,
|
||||
kPrefValueIsUint32,
|
||||
kPrefValueIsCString,
|
||||
kPrefValueIsBoolean
|
||||
};
|
||||
struct Pref {
|
||||
const char* const mPref;
|
||||
@ -45,6 +62,8 @@ protected:
|
||||
void* mAsVoid;
|
||||
StaticAutoPtr<nsCString>* mAsCString;
|
||||
nsresult* mAsNsResult;
|
||||
uint32_t* mAsUint32;
|
||||
bool* mAsBoolean;
|
||||
} mValue;
|
||||
};
|
||||
static Pref sPrefs[];
|
||||
@ -56,6 +75,10 @@ protected:
|
||||
static nsresult sPrefCameraControlMethodErrorOverride;
|
||||
static nsresult sPrefCameraControlAsyncErrorOverride;
|
||||
|
||||
static uint32_t sPrefCameraControlLowMemoryThresholdMB;
|
||||
|
||||
static bool sPrefCameraParametersIsLowMemory;
|
||||
|
||||
private:
|
||||
// static class only
|
||||
CameraPreferences();
|
||||
|
@ -16,12 +16,40 @@
|
||||
|
||||
#include "GonkCameraParameters.h"
|
||||
#include "camera/CameraParameters.h"
|
||||
#include "CameraPreferences.h"
|
||||
#include "ICameraControl.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "mozilla/Hal.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace android;
|
||||
|
||||
/* static */ bool
|
||||
GonkCameraParameters::IsLowMemoryPlatform()
|
||||
{
|
||||
bool testIsLowMem = false;
|
||||
CameraPreferences::GetPref("camera.control.test.is_low_memory", testIsLowMem);
|
||||
if (testIsLowMem) {
|
||||
NS_WARNING("Forcing low-memory platform camera preferences");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t lowMemoryThresholdBytes = 0;
|
||||
CameraPreferences::GetPref("camera.control.low_memory_thresholdMB",
|
||||
lowMemoryThresholdBytes);
|
||||
lowMemoryThresholdBytes *= 1024 * 1024;
|
||||
if (lowMemoryThresholdBytes) {
|
||||
uint32_t totalMemoryBytes = hal::GetTotalSystemMemory();
|
||||
if (totalMemoryBytes < lowMemoryThresholdBytes) {
|
||||
DOM_CAMERA_LOGI("Low-memory platform with %d bytes of RAM (threshold: <%d bytes)\n",
|
||||
totalMemoryBytes, lowMemoryThresholdBytes);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ const char*
|
||||
GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
|
||||
{
|
||||
@ -246,7 +274,7 @@ GonkCameraParameters::Initialize()
|
||||
nsString s;
|
||||
nsTArray<nsCString> isoModes;
|
||||
GetListAsArray(CAMERA_PARAM_SUPPORTED_ISOMODES, isoModes);
|
||||
for (uint32_t i = 0; i < isoModes.Length(); ++i) {
|
||||
for (nsTArray<nsCString>::size_type i = 0; i < isoModes.Length(); ++i) {
|
||||
rv = MapIsoFromGonk(isoModes[i].get(), s);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGW("Unrecognized ISO mode value '%s'\n", isoModes[i].get());
|
||||
@ -256,6 +284,17 @@ GonkCameraParameters::Initialize()
|
||||
mIsoModeMap.Put(s, new nsCString(isoModes[i]));
|
||||
}
|
||||
|
||||
GetListAsArray(CAMERA_PARAM_SUPPORTED_SCENEMODES, mSceneModes);
|
||||
if (IsLowMemoryPlatform()) {
|
||||
bool hdrRemoved = false;
|
||||
while (mSceneModes.RemoveElement(NS_LITERAL_STRING("hdr"))) {
|
||||
hdrRemoved = true;
|
||||
}
|
||||
if (hdrRemoved) {
|
||||
DOM_CAMERA_LOGI("Disabling HDR support due to low memory\n");
|
||||
}
|
||||
}
|
||||
|
||||
mInitialized = true;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -264,16 +303,26 @@ GonkCameraParameters::Initialize()
|
||||
nsresult
|
||||
GonkCameraParameters::SetTranslated(uint32_t aKey, const nsAString& aValue)
|
||||
{
|
||||
if (aKey == CAMERA_PARAM_ISOMODE) {
|
||||
nsAutoCString v;
|
||||
nsresult rv = MapIsoToGonk(aValue, v);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return SetImpl(aKey, v.get());
|
||||
}
|
||||
switch (aKey) {
|
||||
case CAMERA_PARAM_ISOMODE:
|
||||
{
|
||||
nsAutoCString v;
|
||||
nsresult rv = MapIsoToGonk(aValue, v);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return SetImpl(aKey, v.get());
|
||||
}
|
||||
|
||||
return SetImpl(aKey, NS_ConvertUTF16toUTF8(aValue).get());
|
||||
case CAMERA_PARAM_SCENEMODE:
|
||||
if (mSceneModes.IndexOf(aValue) == nsTArray<nsString>::NoIndex) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
default:
|
||||
return SetImpl(aKey, NS_ConvertUTF16toUTF8(aValue).get());
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -620,7 +669,7 @@ GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue)
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, double& aValue)
|
||||
{
|
||||
double val;
|
||||
double val = 0.0; // initialize to keep the compiler happy [-Wmaybe-uninitialized]
|
||||
int index = 0;
|
||||
double focusDistance[3];
|
||||
const char* s;
|
||||
@ -840,12 +889,18 @@ GonkCameraParameters::GetListAsArray(uint32_t aKey, nsTArray<T>& aArray)
|
||||
nsresult
|
||||
GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<nsString>& aValues)
|
||||
{
|
||||
if (aKey == CAMERA_PARAM_SUPPORTED_ISOMODES) {
|
||||
aValues = mIsoModes;
|
||||
return NS_OK;
|
||||
}
|
||||
switch (aKey) {
|
||||
case CAMERA_PARAM_SUPPORTED_ISOMODES:
|
||||
aValues = mIsoModes;
|
||||
return NS_OK;
|
||||
|
||||
return GetListAsArray(aKey, aValues);
|
||||
case CAMERA_PARAM_SUPPORTED_SCENEMODES:
|
||||
aValues = mSceneModes;
|
||||
return NS_OK;
|
||||
|
||||
default:
|
||||
return GetListAsArray(aKey, aValues);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -101,6 +101,7 @@ protected:
|
||||
int32_t mExposureCompensationMaxIndex;
|
||||
nsTArray<int> mZoomRatios;
|
||||
nsTArray<nsString> mIsoModes;
|
||||
nsTArray<nsString> mSceneModes;
|
||||
nsClassHashtable<nsStringHashKey, nsCString> mIsoModeMap;
|
||||
|
||||
// This subclass of android::CameraParameters just gives
|
||||
@ -224,6 +225,10 @@ protected:
|
||||
// Call once to initialize local cached values used in translating other
|
||||
// arguments between Gecko and Gonk. Always returns NS_OK.
|
||||
nsresult Initialize();
|
||||
|
||||
// Returns true if we're a memory-constrained platform that requires
|
||||
// certain features to be disabled; returns false otherwise.
|
||||
static bool IsLowMemoryPlatform();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -35,6 +35,7 @@ var CameraTest = (function() {
|
||||
const PREF_TEST_ENABLED = "camera.control.test.enabled";
|
||||
const PREF_TEST_HARDWARE = "camera.control.test.hardware";
|
||||
const PREF_TEST_EXTRA_PARAMETERS = "camera.control.test.hardware.gonk.parameters";
|
||||
const PREF_TEST_FAKE_LOW_MEMORY = "camera.control.test.is_low_memory";
|
||||
var oldTestEnabled;
|
||||
var oldTestHw;
|
||||
var testMode;
|
||||
@ -53,6 +54,20 @@ var CameraTest = (function() {
|
||||
SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_EXTRA_PARAMETERS]]}, callback);
|
||||
}
|
||||
|
||||
function testHardwareSetFakeLowMemoryPlatform(callback) {
|
||||
SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_FAKE_LOW_MEMORY, true]]}, function() {
|
||||
var setParams = SpecialPowers.getBoolPref(PREF_TEST_FAKE_LOW_MEMORY);
|
||||
ise(setParams, true, "Fake low memory platform");
|
||||
if (callback) {
|
||||
callback(setParams);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testHardwareClearFakeLowMemoryPlatform(callback) {
|
||||
SpecialPowers.pushPrefEnv({'clear': [[PREF_TEST_FAKE_LOW_MEMORY]]}, callback);
|
||||
}
|
||||
|
||||
function testHardwareSet(test, callback) {
|
||||
SpecialPowers.pushPrefEnv({'set': [[PREF_TEST_HARDWARE, test]]}, function() {
|
||||
var setTest = SpecialPowers.getCharPref(PREF_TEST_HARDWARE);
|
||||
@ -88,6 +103,8 @@ var CameraTest = (function() {
|
||||
set: testHardwareSet,
|
||||
setFakeParameters: testHardwareSetFakeParameters,
|
||||
clearFakeParameters: testHardwareClearFakeParameters,
|
||||
setFakeLowMemoryPlatform: testHardwareSetFakeLowMemoryPlatform,
|
||||
clearFakeLowMemoryPlatform: testHardwareClearFakeLowMemoryPlatform,
|
||||
done: testHardwareDone
|
||||
};
|
||||
if (callback) {
|
||||
@ -122,8 +139,16 @@ var CameraTest = (function() {
|
||||
next();
|
||||
}
|
||||
}
|
||||
function cleanUpExtraParameters() {
|
||||
function cleanUpLowMemoryPlatform() {
|
||||
var next = cleanUpTest;
|
||||
if (testMode) {
|
||||
testMode.clearFakeLowMemoryPlatform(next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
function cleanUpExtraParameters() {
|
||||
var next = cleanUpLowMemoryPlatform;
|
||||
if (testMode) {
|
||||
testMode.clearFakeParameters(next);
|
||||
} else {
|
||||
|
@ -114,6 +114,61 @@ var tests = [
|
||||
next();
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "fake-high-memory-platform",
|
||||
prep: function setupFakeHighMemoryPlatform(test) {
|
||||
test.setFakeParameters("scene-mode-values=none,snow,beach,hdr,nothdr", function () {
|
||||
run();
|
||||
});
|
||||
},
|
||||
test: function testFakeHighMemoryPlatform(cam, cap) {
|
||||
ok(cap.sceneModes.length == 5, "scene modes length = " + cap.zoomRatios.length);
|
||||
|
||||
// make sure expected values are present and can be set
|
||||
[ "none", "snow", "beach", "hdr", "nothdr" ].forEach(function(mode) {
|
||||
ok(cap.sceneModes.indexOf(mode) != -1, "Scene mode '" + mode + "' is present");
|
||||
cam.sceneMode = mode;
|
||||
ok(cam.sceneMode == mode, "Scene mode '" + cam.sceneMode + "' is set");
|
||||
});
|
||||
|
||||
next();
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "fake-low-memory-platform",
|
||||
prep: function setupFakeLowMemoryPlatform(test) {
|
||||
test.setFakeLowMemoryPlatform(function() {
|
||||
test.setFakeParameters("scene-mode-values=none,hdr,snow,beach,hdr,nothdr", function () {
|
||||
run();
|
||||
});
|
||||
});
|
||||
},
|
||||
test: function testFakeLowMemoryPlatform(cam, cap) {
|
||||
ok(cap.sceneModes.length == 4, "scene modes length = " + cap.zoomRatios.length);
|
||||
|
||||
// make sure expected values are present and can be set
|
||||
[ "none", "snow", "beach", "nothdr" ].forEach(function(mode) {
|
||||
ok(cap.sceneModes.indexOf(mode) != -1, "Scene mode '" + mode + "' is present");
|
||||
cam.sceneMode = mode;
|
||||
ok(cam.sceneMode == mode, "Scene mode '" + cam.sceneMode + "' is set");
|
||||
});
|
||||
|
||||
// make sure unsupported values have been removed, and can't be set
|
||||
var sceneMode = cam.sceneMode;
|
||||
[ "hdr" ].forEach(function(mode) {
|
||||
ok(cap.sceneModes.indexOf(mode) == -1, "Scene mode '" + mode + "' is not present");
|
||||
try {
|
||||
cam.sceneMode = mode;
|
||||
} catch(e) {
|
||||
}
|
||||
ok(cam.sceneMode != mode, "Scene mode '" + cam.sceneMode + "' is still set, '"
|
||||
+ mode + "' rejected");
|
||||
});
|
||||
ok(cam.sceneMode == sceneMode, "Scene mode '" + cam.sceneMode + "' is still set");
|
||||
|
||||
next();
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "fake-iso",
|
||||
prep: function setupFakeIso(test) {
|
||||
@ -129,20 +184,14 @@ var tests = [
|
||||
ok(cap.isoModes.length == 7, "ISO modes length = " + cap.isoModes.length);
|
||||
|
||||
// make sure we're not leaking any unexpected values formats
|
||||
ok(cap.isoModes.indexOf("ISO_HJR") == -1, "ISO mode 'ISO_HJR' does not appear");
|
||||
ok(cap.isoModes.indexOf("_HJR") == -1, "ISO mode '_HJR' does not appear");
|
||||
ok(cap.isoModes.indexOf("HJR") == -1, "ISO mode 'HJR' does not appear");
|
||||
ok(cap.isoModes.indexOf("ISO100") == -1, "ISO mode 'ISO100' does not appear");
|
||||
ok(cap.isoModes.indexOf("ISO200") == -1, "ISO mode 'ISO200' does not appear");
|
||||
ok(cap.isoModes.indexOf("ISO800") == -1, "ISO mode 'ISO800' does not appear");
|
||||
[ "ISO_HJR", "_HJR", "HJR", "ISO100", "ISO200", "ISO800" ].forEach(function(iso) {
|
||||
ok(cap.isoModes.indexOf(iso) == -1, "ISO mode '" + iso + "' does not appear");
|
||||
});
|
||||
|
||||
// make sure any weird values are dropped entirely
|
||||
ok(cap.isoModes.indexOf("foo") == -1, "Unknown ISO mode 'foo' is ignored");
|
||||
ok(cap.isoModes.indexOf("ISObar") == -1, "Unknown ISO mode 'ISObar' is ignored");
|
||||
ok(cap.isoModes.indexOf("bar") == -1, "Unknown ISO mode 'bar' is ignored");
|
||||
ok(cap.isoModes.indexOf("ISO150moz") == -1, "Unknown ISO mode 'ISO150moz' is ignored");
|
||||
ok(cap.isoModes.indexOf("150moz") == -1, "Unknown ISO mode '150moz' is ignored");
|
||||
ok(cap.isoModes.indexOf("150") == -1, "Unknown ISO mode '150' is ignored");
|
||||
[ "foo", "ISObar", "bar", "ISO150moz", "150moz", "150" ].forEach(function(iso) {
|
||||
ok(cap.isoModes.indexOf(iso) == -1, "Unknown ISO mode '" + iso + "' is ignored");
|
||||
});
|
||||
|
||||
// make sure expected values are present
|
||||
[ "auto", "hjr", "100", "200", "400", "800", "1600" ].forEach(function(iso) {
|
||||
|
@ -4,19 +4,42 @@
|
||||
* 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/. */
|
||||
|
||||
interface BluetoothDevice : EventTarget {
|
||||
readonly attribute DOMString address;
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute DOMString icon;
|
||||
readonly attribute boolean connected;
|
||||
readonly attribute boolean paired;
|
||||
readonly attribute unsigned long class;
|
||||
|
||||
// array of type DOMString[]
|
||||
[Throws]
|
||||
readonly attribute any uuids;
|
||||
|
||||
// array of type DOMString[]
|
||||
[Throws]
|
||||
readonly attribute any services;
|
||||
/*
|
||||
* Set of attributes that might be changed and reported by attributechanged
|
||||
* event.
|
||||
* Address is not included since it should not be changed once BluetoothDevice
|
||||
* is created.
|
||||
*/
|
||||
enum BluetoothDeviceAttribute
|
||||
{
|
||||
"unknown",
|
||||
"cod",
|
||||
"name",
|
||||
"paired",
|
||||
"uuids"
|
||||
};
|
||||
|
||||
[CheckPermissions="bluetooth"]
|
||||
interface BluetoothDevice : EventTarget
|
||||
{
|
||||
readonly attribute DOMString address;
|
||||
readonly attribute BluetoothClassOfDevice cod;
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute boolean paired;
|
||||
|
||||
[Cached, Pure]
|
||||
readonly attribute sequence<DOMString> uuids;
|
||||
|
||||
attribute EventHandler onattributechanged;
|
||||
|
||||
/**
|
||||
* Fetch the up-to-date UUID list of each bluetooth service that the device
|
||||
* provides and refresh the cache value of attribute uuids if it is updated.
|
||||
*
|
||||
* If the operation succeeds, the promise will be resolved with up-to-date
|
||||
* UUID list which is identical to attribute uuids.
|
||||
*/
|
||||
// Promise<sequence<DOMString>>
|
||||
[NewObject, Throws]
|
||||
Promise fetchUuids();
|
||||
};
|
||||
|
@ -240,6 +240,9 @@ this.WifiCommand = function(aControlMessage, aInterface, aSdkVersion) {
|
||||
});
|
||||
};
|
||||
|
||||
let infoKeys = [{regexp: /RSSI=/i, prop: 'rssi'},
|
||||
{regexp: /LINKSPEED=/i, prop: 'linkspeed'}];
|
||||
|
||||
command.getConnectionInfoICS = function (callback) {
|
||||
doStringCommand("SIGNAL_POLL", function(reply) {
|
||||
if (!reply) {
|
||||
@ -247,19 +250,21 @@ this.WifiCommand = function(aControlMessage, aInterface, aSdkVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find any values matching |infoKeys|. This gets executed frequently
|
||||
// enough that we want to avoid creating intermediate strings as much as
|
||||
// possible.
|
||||
let rval = {};
|
||||
var lines = reply.split("\n");
|
||||
for (let i = 0; i < lines.length; ++i) {
|
||||
let [key, value] = lines[i].split("=");
|
||||
switch (key.toUpperCase()) {
|
||||
case "RSSI":
|
||||
rval.rssi = value | 0;
|
||||
break;
|
||||
case "LINKSPEED":
|
||||
rval.linkspeed = value | 0;
|
||||
break;
|
||||
default:
|
||||
// Ignore.
|
||||
for (let i = 0; i < infoKeys.length; i++) {
|
||||
let re = infoKeys[i].regexp;
|
||||
let iKeyStart = reply.search(re);
|
||||
if (iKeyStart !== -1) {
|
||||
let prop = infoKeys[i].prop;
|
||||
let iValueStart = reply.indexOf('=', iKeyStart) + 1;
|
||||
let iNewlineAfterValue = reply.indexOf('\n', iValueStart);
|
||||
let iValueEnd = iNewlineAfterValue !== -1
|
||||
? iNewlineAfterValue
|
||||
: reply.length;
|
||||
rval[prop] = reply.substring(iValueStart, iValueEnd) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4273,3 +4273,11 @@ pref("beacon.enabled", true);
|
||||
// Camera prefs
|
||||
pref("camera.control.autofocus_moving_callback.enabled", true);
|
||||
pref("camera.control.face_detection.enabled", true);
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Empirically, this is the value returned by hal::GetTotalSystemMemory()
|
||||
// when Flame's memory is limited to 512MiB. If the camera stack determines
|
||||
// it is running on a low memory platform, features that can be reliably
|
||||
// supported will be disabled. This threshold can be adjusted to suit other
|
||||
// platforms; and set to 0 to disable the low-memory check altogether.
|
||||
pref("camera.control.low_memory_thresholdMB", 404);
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user