зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound. a=merge
This commit is contained in:
Коммит
1022db7d1e
|
@ -15,9 +15,9 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
<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="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
<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="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "31e595f86f6bf159b3a9a46816a6ac00a55ca9f9",
|
||||
"git_revision": "c80e8ff25425b007181fd6e3de0500a0358fab37",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "15ba43fc66bdea9bfe6397bb992c0918d9d3d77c",
|
||||
"revision": "617c2b44e26a8bd8c79d96a12fb9fd373c873e44",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="31e595f86f6bf159b3a9a46816a6ac00a55ca9f9"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c80e8ff25425b007181fd6e3de0500a0358fab37"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -48,7 +48,7 @@ AppValidator.prototype._getPackagedManifestFile = function () {
|
|||
let hasJsonManifest = jsonManifestFile.exists() && jsonManifestFile.isFile();
|
||||
|
||||
if (!hasAppManifest && !hasJsonManifest) {
|
||||
this.error(strings.GetStringFromName("validator.wrongManifestFileName"));
|
||||
this.error(strings.GetStringFromName("validator.noManifestFile"));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -338,7 +338,7 @@ let PerformanceController = {
|
|||
*/
|
||||
exportRecording: Task.async(function*(_, recording, file) {
|
||||
yield recording.exportRecording(file);
|
||||
this.emit(EVENTS.RECORDING_EXPORTED, recording);
|
||||
this.emit(EVENTS.RECORDING_EXPORTED, recording, file);
|
||||
}),
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
let test = Task.async(function*() {
|
||||
var { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
|
||||
var { EVENTS, PerformanceController, PerformanceView, DetailsView, DetailsSubview } = panel.panelWin;
|
||||
var { $, EVENTS, PerformanceController, PerformanceView, DetailsView, DetailsSubview } = panel.panelWin;
|
||||
|
||||
// Enable allocations to test the memory-calltree and memory-flamegraph.
|
||||
Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
|
||||
|
@ -45,6 +45,13 @@ let test = Task.async(function*() {
|
|||
yield exported;
|
||||
ok(true, "The recording data appears to have been successfully saved.");
|
||||
|
||||
// Check if the imported file name has tmpprofile in it as the file
|
||||
// names also has different suffix to avoid conflict
|
||||
|
||||
let displayedName = $(".recording-item-title").getAttribute("value");
|
||||
ok(/^tmpprofile/.test(displayedName), "File has expected display name after import");
|
||||
ok(!/\.json$/.test(displayedName), "Display name does not have .json in it");
|
||||
|
||||
// Import recording.
|
||||
|
||||
let rerendered = waitForWidgetsRendered(panel);
|
||||
|
|
|
@ -18,12 +18,14 @@ let RecordingsView = Heritage.extend(WidgetMethods, {
|
|||
this._onNewRecording = this._onNewRecording.bind(this);
|
||||
this._onSaveButtonClick = this._onSaveButtonClick.bind(this);
|
||||
this._onRecordingsCleared = this._onRecordingsCleared.bind(this);
|
||||
this._onRecordingExported = this._onRecordingExported.bind(this);
|
||||
|
||||
this.emptyText = L10N.getStr("noRecordingsText");
|
||||
|
||||
PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
|
||||
PerformanceController.on(EVENTS.NEW_RECORDING, this._onNewRecording);
|
||||
PerformanceController.on(EVENTS.RECORDINGS_CLEARED, this._onRecordingsCleared);
|
||||
PerformanceController.on(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
|
||||
this.widget.addEventListener("select", this._onSelect, false);
|
||||
},
|
||||
|
||||
|
@ -34,6 +36,7 @@ let RecordingsView = Heritage.extend(WidgetMethods, {
|
|||
PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
|
||||
PerformanceController.off(EVENTS.NEW_RECORDING, this._onNewRecording);
|
||||
PerformanceController.off(EVENTS.RECORDINGS_CLEARED, this._onRecordingsCleared);
|
||||
PerformanceController.off(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
|
||||
this.widget.removeEventListener("select", this._onSelect, false);
|
||||
},
|
||||
|
||||
|
@ -197,6 +200,15 @@ let RecordingsView = Heritage.extend(WidgetMethods, {
|
|||
}});
|
||||
},
|
||||
|
||||
_onRecordingExported: function (_, recording, file) {
|
||||
if (recording.isConsole()) {
|
||||
return;
|
||||
}
|
||||
let recordingItem = this.getItemForPredicate(e => e.attachment === recording);
|
||||
let titleNode = $(".recording-item-title", recordingItem.target);
|
||||
titleNode.setAttribute("value", file.leafName.replace(/\..+$/, ""));
|
||||
},
|
||||
|
||||
toString: () => "[object RecordingsView]"
|
||||
});
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ project.installing=Installing…
|
|||
project.installed=Installed!
|
||||
validator.nonExistingFolder=The project folder doesn't exists
|
||||
validator.expectProjectFolder=The project folder ends up being a file
|
||||
validator.wrongManifestFileName=A manifest file is required at project root folder, named either 'manifest.webapp' for packaged apps or 'manifest.json' for addons.
|
||||
validator.noManifestFile=A manifest file is required at project root folder, named either 'manifest.webapp' for packaged apps or 'manifest.json' for add-ons.
|
||||
validator.invalidManifestURL=Invalid manifest URL '%S'
|
||||
# LOCALIZATION NOTE (validator.invalidManifestJSON, validator.noAccessManifestURL):
|
||||
# %1$S is the error message, %2$S is the URI of the manifest.
|
||||
|
|
|
@ -96,6 +96,7 @@
|
|||
#include "nsSHistory.h"
|
||||
#include "nsDocShellEditorData.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "timeline/JavascriptTimelineMarker.h"
|
||||
|
||||
// Helper Classes
|
||||
#include "nsError.h"
|
||||
|
@ -1601,7 +1602,7 @@ nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
|
|||
(void)aLoadInfo->GetLoadType(<);
|
||||
// Get the appropriate LoadType from nsIDocShellLoadInfo type
|
||||
loadType = ConvertDocShellLoadInfoToLoadType(lt);
|
||||
|
||||
|
||||
nsCOMPtr<nsISupports> owner;
|
||||
aLoadInfo->GetOwner(getter_AddRefs(owner));
|
||||
requestingPrincipal = do_QueryInterface(owner);
|
||||
|
@ -13763,51 +13764,6 @@ nsDocShell::GetOpener()
|
|||
return opener;
|
||||
}
|
||||
|
||||
class JavascriptTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
JavascriptTimelineMarker(nsDocShell* aDocShell, const char* aName,
|
||||
const char* aReason,
|
||||
const char16_t* aFunctionName,
|
||||
const char16_t* aFileName,
|
||||
uint32_t aLineNumber)
|
||||
: TimelineMarker(aDocShell, aName, TRACING_INTERVAL_START,
|
||||
NS_ConvertUTF8toUTF16(aReason),
|
||||
NO_STACK)
|
||||
, mFunctionName(aFunctionName)
|
||||
, mFileName(aFileName)
|
||||
, mLineNumber(aLineNumber)
|
||||
{
|
||||
}
|
||||
|
||||
void AddDetails(JSContext* aCx, mozilla::dom::ProfileTimelineMarker& aMarker)
|
||||
override
|
||||
{
|
||||
aMarker.mCauseName.Construct(GetCause());
|
||||
|
||||
if (!mFunctionName.IsEmpty() || !mFileName.IsEmpty()) {
|
||||
RootedDictionary<ProfileTimelineStackFrame> stackFrame(aCx);
|
||||
stackFrame.mLine.Construct(mLineNumber);
|
||||
stackFrame.mSource.Construct(mFileName);
|
||||
stackFrame.mFunctionDisplayName.Construct(mFunctionName);
|
||||
|
||||
JS::Rooted<JS::Value> newStack(aCx);
|
||||
if (ToJSValue(aCx, stackFrame, &newStack)) {
|
||||
if (newStack.isObject()) {
|
||||
aMarker.mStack = &newStack.toObject();
|
||||
}
|
||||
} else {
|
||||
JS_ClearPendingException(aCx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mFunctionName;
|
||||
nsString mFileName;
|
||||
uint32_t mLineNumber;
|
||||
};
|
||||
|
||||
void
|
||||
nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
|
||||
const char16_t* aFunctionName,
|
||||
|
@ -13818,10 +13774,8 @@ nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
|
|||
|
||||
// If first start, mark interval start.
|
||||
if (timelineOn && mJSRunToCompletionDepth == 0) {
|
||||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<JavascriptTimelineMarker>(this, "Javascript", aReason,
|
||||
aFunctionName, aFilename,
|
||||
aLineNumber);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<JavascriptTimelineMarker>(
|
||||
aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(this, Move(marker));
|
||||
}
|
||||
mJSRunToCompletionDepth++;
|
||||
|
@ -13835,7 +13789,7 @@ nsDocShell::NotifyJSRunToCompletionStop()
|
|||
// If last stop, mark interval end.
|
||||
mJSRunToCompletionDepth--;
|
||||
if (timelineOn && mJSRunToCompletionDepth == 0) {
|
||||
TimelineConsumers::AddMarkerForDocShell(this, "Javascript", TRACING_INTERVAL_END);
|
||||
TimelineConsumers::AddMarkerForDocShell(this, "Javascript", MarkerTracingType::END);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@
|
|||
#include "nsAutoPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "timeline/TimelineMarker.h"
|
||||
#include "timeline/TimelineConsumers.h"
|
||||
#include "timeline/ObservedDocShell.h"
|
||||
#include "timeline/TimelineConsumers.h"
|
||||
#include "timeline/TimelineMarker.h"
|
||||
|
||||
// Threshold value in ms for META refresh based redirects
|
||||
#define REFRESH_REDIRECT_TIMER 15000
|
||||
|
@ -275,14 +275,14 @@ private:
|
|||
// be very fast, so instead of using a Map or having to search for some
|
||||
// docshell-specific markers storage, a pointer to an `ObservedDocShell` is
|
||||
// is stored on docshells directly.
|
||||
friend void mozilla::TimelineConsumers::AddConsumer(nsDocShell* aDocShell);
|
||||
friend void mozilla::TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell);
|
||||
friend void mozilla::TimelineConsumers::AddConsumer(nsDocShell*);
|
||||
friend void mozilla::TimelineConsumers::RemoveConsumer(nsDocShell*);
|
||||
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
|
||||
nsDocShell* aDocShell, const char* aName, TracingMetadata aMetaData);
|
||||
nsDocShell*, const char*, MarkerTracingType);
|
||||
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
|
||||
nsDocShell* aDocShell, const char* aName, const TimeStamp& aTime, TracingMetadata aMetaData);
|
||||
nsDocShell*, const char*, const TimeStamp&, MarkerTracingType);
|
||||
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
|
||||
nsDocShell* aDocShell, UniquePtr<TimelineMarker>&& aMarker);
|
||||
nsDocShell*, UniquePtr<TimelineMarker>&&);
|
||||
|
||||
public:
|
||||
// Tell the favicon service that aNewURI has the same favicon as aOldURI.
|
||||
|
|
|
@ -22,7 +22,7 @@ AutoGlobalTimelineMarker::AutoGlobalTimelineMarker(const char* aName
|
|||
return;
|
||||
}
|
||||
|
||||
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, TRACING_INTERVAL_START);
|
||||
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, MarkerTracingType::START);
|
||||
}
|
||||
|
||||
AutoGlobalTimelineMarker::~AutoGlobalTimelineMarker()
|
||||
|
@ -31,7 +31,7 @@ AutoGlobalTimelineMarker::~AutoGlobalTimelineMarker()
|
|||
return;
|
||||
}
|
||||
|
||||
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, TRACING_INTERVAL_END);
|
||||
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, MarkerTracingType::END);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace mozilla {
|
|||
// Similar to `AutoTimelineMarker`, but adds its traced marker to all docshells,
|
||||
// not a single particular one. This is useful for operations that aren't
|
||||
// associated with any one particular doc shell, or when it isn't clear which
|
||||
// doc shell triggered the operation.
|
||||
// docshell triggered the operation.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
|
|
|
@ -25,7 +25,7 @@ AutoTimelineMarker::AutoTimelineMarker(nsIDocShell* aDocShell, const char* aName
|
|||
}
|
||||
|
||||
mDocShell = static_cast<nsDocShell*>(aDocShell);
|
||||
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, TRACING_INTERVAL_START);
|
||||
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, MarkerTracingType::START);
|
||||
}
|
||||
|
||||
AutoTimelineMarker::~AutoTimelineMarker()
|
||||
|
@ -34,7 +34,7 @@ AutoTimelineMarker::~AutoTimelineMarker()
|
|||
return;
|
||||
}
|
||||
|
||||
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, TRACING_INTERVAL_END);
|
||||
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, MarkerTracingType::END);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ConsoleTimelineMarker_h_
|
||||
#define mozilla_ConsoleTimelineMarker_h_
|
||||
|
||||
#include "TimelineMarker.h"
|
||||
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ConsoleTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
explicit ConsoleTimelineMarker(const nsAString& aCause,
|
||||
MarkerTracingType aTracingType)
|
||||
: TimelineMarker("ConsoleTime", aTracingType)
|
||||
, mCause(aCause)
|
||||
{
|
||||
// Stack is captured by default on the "start" marker. Explicitly also
|
||||
// capture stack on the "end" marker.
|
||||
if (aTracingType == MarkerTracingType::END) {
|
||||
CaptureStack();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool Equals(const TimelineMarker& aOther) override
|
||||
{
|
||||
if (!TimelineMarker::Equals(aOther)) {
|
||||
return false;
|
||||
}
|
||||
// Console markers must have matching causes as well. It is safe to perform
|
||||
// a static_cast here as the previous equality check ensures that this is
|
||||
// a console marker instance.
|
||||
return mCause == static_cast<const ConsoleTimelineMarker*>(&aOther)->mCause;
|
||||
}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
if (GetTracingType() == MarkerTracingType::START) {
|
||||
aMarker.mCauseName.Construct(mCause);
|
||||
} else {
|
||||
aMarker.mEndStack = GetStack();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mCause;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ConsoleTimelineMarker_h_
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_EventTimelineMarker_h_
|
||||
#define mozilla_EventTimelineMarker_h_
|
||||
|
||||
#include "TimelineMarker.h"
|
||||
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EventTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
explicit EventTimelineMarker(const nsAString& aType,
|
||||
uint16_t aPhase,
|
||||
MarkerTracingType aTracingType)
|
||||
: TimelineMarker("DOMEvent", aTracingType)
|
||||
, mType(aType)
|
||||
, mPhase(aPhase)
|
||||
{}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
if (GetTracingType() == MarkerTracingType::START) {
|
||||
aMarker.mType.Construct(mType);
|
||||
aMarker.mEventPhase.Construct(mPhase);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mType;
|
||||
uint16_t mPhase;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_EventTimelineMarker_h_
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_JavascriptTimelineMarker_h_
|
||||
#define mozilla_JavascriptTimelineMarker_h_
|
||||
|
||||
#include "TimelineMarker.h"
|
||||
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
||||
#include "mozilla/dom/RootedDictionary.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class JavascriptTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
explicit JavascriptTimelineMarker(const char* aReason,
|
||||
const char16_t* aFunctionName,
|
||||
const char16_t* aFileName,
|
||||
uint32_t aLineNumber,
|
||||
MarkerTracingType aTracingType)
|
||||
: TimelineMarker("Javascript", aTracingType, MarkerStackRequest::NO_STACK)
|
||||
, mCause(NS_ConvertUTF8toUTF16(aReason))
|
||||
, mFunctionName(aFunctionName)
|
||||
, mFileName(aFileName)
|
||||
, mLineNumber(aLineNumber)
|
||||
{}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
aMarker.mCauseName.Construct(mCause);
|
||||
|
||||
if (!mFunctionName.IsEmpty() || !mFileName.IsEmpty()) {
|
||||
dom::RootedDictionary<dom::ProfileTimelineStackFrame> stackFrame(aCx);
|
||||
stackFrame.mLine.Construct(mLineNumber);
|
||||
stackFrame.mSource.Construct(mFileName);
|
||||
stackFrame.mFunctionDisplayName.Construct(mFunctionName);
|
||||
|
||||
JS::Rooted<JS::Value> newStack(aCx);
|
||||
if (ToJSValue(aCx, stackFrame, &newStack)) {
|
||||
if (newStack.isObject()) {
|
||||
aMarker.mStack = &newStack.toObject();
|
||||
}
|
||||
} else {
|
||||
JS_ClearPendingException(aCx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mCause;
|
||||
nsString mFunctionName;
|
||||
nsString mFileName;
|
||||
uint32_t mLineNumber;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_JavascriptTimelineMarker_h_
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_LayerTimelineMarker_h_
|
||||
#define mozilla_LayerTimelineMarker_h_
|
||||
|
||||
#include "TimelineMarker.h"
|
||||
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class LayerTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
explicit LayerTimelineMarker(const nsIntRegion& aRegion)
|
||||
: TimelineMarker("Layer", MarkerTracingType::HELPER_EVENT)
|
||||
, mRegion(aRegion)
|
||||
{}
|
||||
|
||||
~LayerTimelineMarker()
|
||||
{}
|
||||
|
||||
void AddLayerRectangles(dom::Sequence<dom::ProfileTimelineLayerRect>& aRectangles)
|
||||
{
|
||||
nsIntRegionRectIterator it(mRegion);
|
||||
while (const nsIntRect* iterRect = it.Next()) {
|
||||
dom::ProfileTimelineLayerRect rect;
|
||||
rect.mX = iterRect->X();
|
||||
rect.mY = iterRect->Y();
|
||||
rect.mWidth = iterRect->Width();
|
||||
rect.mHeight = iterRect->Height();
|
||||
aRectangles.AppendElement(rect, fallible);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsIntRegion mRegion;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_LayerTimelineMarker_h_
|
|
@ -7,6 +7,7 @@
|
|||
#include "ObservedDocShell.h"
|
||||
|
||||
#include "TimelineMarker.h"
|
||||
#include "LayerTimelineMarker.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -38,9 +39,9 @@ ObservedDocShell::PopMarkers(JSContext* aCx,
|
|||
for (uint32_t i = 0; i < mTimelineMarkers.Length(); ++i) {
|
||||
UniquePtr<TimelineMarker>& startPayload = mTimelineMarkers[i];
|
||||
|
||||
// If this is a TRACING_TIMESTAMP marker, there's no corresponding END
|
||||
// If this is a TIMESTAMP marker, there's no corresponding END,
|
||||
// as it's a single unit of time, not a duration.
|
||||
if (startPayload->GetMetaData() == TRACING_TIMESTAMP) {
|
||||
if (startPayload->GetTracingType() == MarkerTracingType::TIMESTAMP) {
|
||||
dom::ProfileTimelineMarker* marker = aStore.AppendElement();
|
||||
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
|
||||
marker->mStart = startPayload->GetTime();
|
||||
|
@ -52,7 +53,7 @@ ObservedDocShell::PopMarkers(JSContext* aCx,
|
|||
|
||||
// Whenever a START marker is found, look for the corresponding END
|
||||
// and build a {name,start,end} JS object.
|
||||
if (startPayload->GetMetaData() == TRACING_INTERVAL_START) {
|
||||
if (startPayload->GetTracingType() == MarkerTracingType::START) {
|
||||
bool hasSeenEnd = false;
|
||||
|
||||
// "Paint" markers are different because painting is handled at root
|
||||
|
@ -80,17 +81,18 @@ ObservedDocShell::PopMarkers(JSContext* aCx,
|
|||
|
||||
// Look for "Layer" markers to stream out "Paint" markers.
|
||||
if (startIsPaintType && endIsLayerType) {
|
||||
LayerTimelineMarker* layerPayload = static_cast<LayerTimelineMarker*>(endPayload.get());
|
||||
layerPayload->AddLayerRectangles(layerRectangles);
|
||||
hasSeenLayerType = true;
|
||||
endPayload->AddLayerRectangles(layerRectangles);
|
||||
}
|
||||
if (!startPayload->Equals(*endPayload)) {
|
||||
continue;
|
||||
}
|
||||
if (endPayload->GetMetaData() == TRACING_INTERVAL_START) {
|
||||
if (endPayload->GetTracingType() == MarkerTracingType::START) {
|
||||
++markerDepth;
|
||||
continue;
|
||||
}
|
||||
if (endPayload->GetMetaData() == TRACING_INTERVAL_END) {
|
||||
if (endPayload->GetTracingType() == MarkerTracingType::END) {
|
||||
if (markerDepth > 0) {
|
||||
--markerDepth;
|
||||
continue;
|
||||
|
|
|
@ -4,16 +4,17 @@
|
|||
* 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 ObservedDocShell_h_
|
||||
#define ObservedDocShell_h_
|
||||
#ifndef mozilla_ObservedDocShell_h_
|
||||
#define mozilla_ObservedDocShell_h_
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
|
||||
class nsDocShell;
|
||||
class TimelineMarker;
|
||||
|
||||
namespace mozilla {
|
||||
class TimelineMarker;
|
||||
|
||||
namespace dom {
|
||||
struct ProfileTimelineMarker;
|
||||
}
|
||||
|
@ -39,4 +40,4 @@ public:
|
|||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* ObservedDocShell_h_ */
|
||||
#endif /* mozilla_ObservedDocShell_h_ */
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_RestyleTimelineMarker_h_
|
||||
#define mozilla_RestyleTimelineMarker_h_
|
||||
|
||||
#include "TimelineMarker.h"
|
||||
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class RestyleTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
explicit RestyleTimelineMarker(nsRestyleHint aRestyleHint,
|
||||
MarkerTracingType aTracingType)
|
||||
: TimelineMarker("Styles", aTracingType)
|
||||
{
|
||||
if (aRestyleHint) {
|
||||
mRestyleHint.AssignWithConversion(RestyleManager::RestyleHintToString(aRestyleHint));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
if (GetTracingType() == MarkerTracingType::START) {
|
||||
aMarker.mRestyleHint.Construct(mRestyleHint);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoString mRestyleHint;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_RestyleTimelineMarker_h_
|
|
@ -68,10 +68,10 @@ TimelineConsumers::GetKnownDocShells(Vector<nsRefPtr<nsDocShell>>& aStore)
|
|||
void
|
||||
TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
const char* aName,
|
||||
TracingMetadata aMetaData)
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
if (aDocShell->IsObserved()) {
|
||||
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aDocShell, aName, aMetaData)));
|
||||
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTracingType)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,10 +79,10 @@ void
|
|||
TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
TracingMetadata aMetaData)
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
if (aDocShell->IsObserved()) {
|
||||
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aDocShell, aName, aTime, aMetaData)));
|
||||
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTime, aTracingType)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,18 +98,18 @@ TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
|
|||
void
|
||||
TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
const char* aName,
|
||||
TracingMetadata aMetaData)
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aMetaData);
|
||||
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTracingType);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
TracingMetadata aMetaData)
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTime, aMetaData);
|
||||
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTime, aTracingType);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -122,18 +122,18 @@ TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
|
|||
void
|
||||
TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
|
||||
const char* aName,
|
||||
TracingMetadata aMetaData)
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
|
||||
!range.empty();
|
||||
range.popFront()) {
|
||||
AddMarkerForDocShell(range.front(), aName, aMetaData);
|
||||
AddMarkerForDocShell(range.front(), aName, aTracingType);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
|
||||
TracingMetadata aMetaData)
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
Vector<nsRefPtr<nsDocShell>> docShells;
|
||||
if (!GetKnownDocShells(docShells)) {
|
||||
|
@ -142,7 +142,7 @@ TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
|
|||
return;
|
||||
}
|
||||
|
||||
AddMarkerForDocShellsList(docShells, aName, aMetaData);
|
||||
AddMarkerForDocShellsList(docShells, aName, aTracingType);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -10,14 +10,16 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#include "TimelineMarkerEnums.h"
|
||||
|
||||
class nsDocShell;
|
||||
class nsIDocShell;
|
||||
class TimelineMarker;
|
||||
|
||||
namespace mozilla {
|
||||
class ObservedDocShell;
|
||||
class TimelineMarker;
|
||||
|
||||
class TimelineConsumers
|
||||
{
|
||||
|
@ -46,19 +48,19 @@ public:
|
|||
// relevant for a specific docshell.
|
||||
static void AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
const char* aName,
|
||||
TracingMetadata aMetaData);
|
||||
MarkerTracingType aTracingType);
|
||||
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
const char* aName,
|
||||
TracingMetadata aMetaData);
|
||||
MarkerTracingType aTracingType);
|
||||
|
||||
static void AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
TracingMetadata aMetaData);
|
||||
MarkerTracingType aTracingType);
|
||||
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
TracingMetadata aMetaData);
|
||||
MarkerTracingType aTracingType);
|
||||
|
||||
// These methods register and receive ownership of an already created marker,
|
||||
// relevant for a specific docshell.
|
||||
|
@ -70,12 +72,12 @@ public:
|
|||
// This method creates custom markers, relevant for a list of docshells.
|
||||
static void AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
|
||||
const char* aName,
|
||||
TracingMetadata aMetaData);
|
||||
MarkerTracingType aTracingType);
|
||||
|
||||
// This method creates custom markers, none of which have to be tied to a
|
||||
// particular docshell.
|
||||
static void AddMarkerForAllObservedDocShells(const char* aName,
|
||||
TracingMetadata aMetaData);
|
||||
MarkerTracingType aTracingType);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -4,50 +4,61 @@
|
|||
* 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 "nsDocShell.h"
|
||||
#include "TimelineMarker.h"
|
||||
|
||||
TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName,
|
||||
TracingMetadata aMetaData)
|
||||
namespace mozilla {
|
||||
|
||||
TimelineMarker::TimelineMarker(const char* aName,
|
||||
MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest)
|
||||
: mName(aName)
|
||||
, mMetaData(aMetaData)
|
||||
, mTracingType(aTracingType)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TimelineMarker);
|
||||
MOZ_ASSERT(aName);
|
||||
aDocShell->Now(&mTime);
|
||||
if (aMetaData == TRACING_INTERVAL_START || aMetaData == TRACING_TIMESTAMP) {
|
||||
CaptureStack();
|
||||
}
|
||||
SetCurrentTime();
|
||||
CaptureStackIfNecessary(aTracingType, aStackRequest);
|
||||
}
|
||||
|
||||
TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName,
|
||||
const mozilla::TimeStamp& aTime,
|
||||
TracingMetadata aMetaData)
|
||||
: TimelineMarker(aDocShell, aName, aMetaData)
|
||||
{
|
||||
bool isInconsistent = false;
|
||||
mTime = (aTime - mozilla::TimeStamp::ProcessCreation(isInconsistent)).ToMilliseconds();
|
||||
}
|
||||
|
||||
TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName,
|
||||
TracingMetadata aMetaData,
|
||||
const nsAString& aCause,
|
||||
TimelineStackRequest aStackRequest)
|
||||
TimelineMarker::TimelineMarker(const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest)
|
||||
: mName(aName)
|
||||
, mMetaData(aMetaData)
|
||||
, mCause(aCause)
|
||||
, mTracingType(aTracingType)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TimelineMarker);
|
||||
MOZ_ASSERT(aName);
|
||||
aDocShell->Now(&mTime);
|
||||
if ((aMetaData == TRACING_INTERVAL_START ||
|
||||
aMetaData == TRACING_TIMESTAMP) &&
|
||||
aStackRequest != NO_STACK) {
|
||||
CaptureStack();
|
||||
}
|
||||
SetCustomTime(aTime);
|
||||
CaptureStackIfNecessary(aTracingType, aStackRequest);
|
||||
}
|
||||
|
||||
TimelineMarker::~TimelineMarker()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TimelineMarker);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineMarker::SetCurrentTime()
|
||||
{
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
SetCustomTime(now);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineMarker::SetCustomTime(const TimeStamp& aTime)
|
||||
{
|
||||
bool isInconsistent = false;
|
||||
mTime = (aTime - TimeStamp::ProcessCreation(isInconsistent)).ToMilliseconds();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineMarker::CaptureStackIfNecessary(MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest)
|
||||
{
|
||||
if ((aTracingType == MarkerTracingType::START ||
|
||||
aTracingType == MarkerTracingType::TIMESTAMP) &&
|
||||
aStackRequest != MarkerStackRequest::NO_STACK) {
|
||||
CaptureStack();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -4,66 +4,54 @@
|
|||
* 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 TimelineMarker_h_
|
||||
#define TimelineMarker_h_
|
||||
#ifndef mozilla_TimelineMarker_h_
|
||||
#define mozilla_TimelineMarker_h_
|
||||
|
||||
#include "nsString.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "jsapi.h"
|
||||
#include "TimelineMarkerEnums.h"
|
||||
|
||||
class nsDocShell;
|
||||
|
||||
// Objects of this type can be added to the timeline. The class can
|
||||
// also be subclassed to let a given marker creator provide custom
|
||||
// details.
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
struct ProfileTimelineMarker;
|
||||
}
|
||||
|
||||
// Objects of this type can be added to the timeline if there is an interested
|
||||
// consumer. The class can also be subclassed to let a given marker creator
|
||||
// provide custom details.
|
||||
class TimelineMarker
|
||||
{
|
||||
public:
|
||||
enum TimelineStackRequest { STACK, NO_STACK };
|
||||
TimelineMarker(const char* aName,
|
||||
MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest = MarkerStackRequest::STACK);
|
||||
|
||||
TimelineMarker(nsDocShell* aDocShell, const char* aName,
|
||||
TracingMetadata aMetaData);
|
||||
|
||||
TimelineMarker(nsDocShell* aDocShell, const char* aName,
|
||||
const mozilla::TimeStamp& aTime,
|
||||
TracingMetadata aMetaData);
|
||||
|
||||
TimelineMarker(nsDocShell* aDocShell, const char* aName,
|
||||
TracingMetadata aMetaData,
|
||||
const nsAString& aCause,
|
||||
TimelineStackRequest aStackRequest = STACK);
|
||||
TimelineMarker(const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest = MarkerStackRequest::STACK);
|
||||
|
||||
virtual ~TimelineMarker();
|
||||
|
||||
// Check whether two markers should be considered the same,
|
||||
// for the purpose of pairing start and end markers. Normally
|
||||
// this definition suffices.
|
||||
// Check whether two markers should be considered the same, for the purpose
|
||||
// of pairing start and end markers. Normally this definition suffices.
|
||||
virtual bool Equals(const TimelineMarker& aOther)
|
||||
{
|
||||
return strcmp(mName, aOther.mName) == 0;
|
||||
}
|
||||
|
||||
// Add details specific to this marker type to aMarker. The
|
||||
// standard elements have already been set. This method is
|
||||
// called on both the starting and ending markers of a pair.
|
||||
// Ordinarily the ending marker doesn't need to do anything
|
||||
// here.
|
||||
virtual void AddDetails(JSContext* aCx,
|
||||
mozilla::dom::ProfileTimelineMarker& aMarker)
|
||||
// Add details specific to this marker type to aMarker. The standard elements
|
||||
// have already been set. This method is called on both the starting and
|
||||
// ending markers of a pair. Ordinarily the ending marker doesn't need to do
|
||||
// anything here.
|
||||
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker)
|
||||
{}
|
||||
|
||||
virtual void AddLayerRectangles(
|
||||
mozilla::dom::Sequence<mozilla::dom::ProfileTimelineLayerRect>&)
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("can only be called on layer markers");
|
||||
}
|
||||
|
||||
const char* GetName() const { return mName; }
|
||||
TracingMetadata GetMetaData() const { return mMetaData; }
|
||||
DOMHighResTimeStamp GetTime() const { return mTime; }
|
||||
const nsString& GetCause() const { return mCause; }
|
||||
MarkerTracingType GetTracingType() const { return mTracingType; }
|
||||
|
||||
JSObject* GetStack()
|
||||
{
|
||||
|
@ -89,15 +77,21 @@ protected:
|
|||
|
||||
private:
|
||||
const char* mName;
|
||||
TracingMetadata mMetaData;
|
||||
DOMHighResTimeStamp mTime;
|
||||
nsString mCause;
|
||||
MarkerTracingType mTracingType;
|
||||
|
||||
// While normally it is not a good idea to make a persistent root,
|
||||
// in this case changing nsDocShell to participate in cycle
|
||||
// collection was deemed too invasive, and the markers are only held
|
||||
// here temporarily to boot.
|
||||
JS::PersistentRooted<JSObject*> mStackTrace;
|
||||
|
||||
void SetCurrentTime();
|
||||
void SetCustomTime(const TimeStamp& aTime);
|
||||
void CaptureStackIfNecessary(MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest);
|
||||
};
|
||||
|
||||
#endif /* TimelineMarker_h_ */
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_TimelineMarker_h_ */
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_TimelineMarkerEnums_h_
|
||||
#define mozilla_TimelineMarkerEnums_h_
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
enum class MarkerTracingType {
|
||||
START,
|
||||
END,
|
||||
TIMESTAMP,
|
||||
HELPER_EVENT
|
||||
};
|
||||
|
||||
enum class MarkerStackRequest {
|
||||
STACK,
|
||||
NO_STACK
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_TimelineMarkerEnums_h_
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_TimestampTimelineMarker_h_
|
||||
#define mozilla_TimestampTimelineMarker_h_
|
||||
|
||||
#include "TimelineMarker.h"
|
||||
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class TimestampTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
explicit TimestampTimelineMarker(const nsAString& aCause)
|
||||
: TimelineMarker("TimeStamp", MarkerTracingType::TIMESTAMP)
|
||||
, mCause(aCause)
|
||||
{}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
if (!mCause.IsEmpty()) {
|
||||
aMarker.mCauseName.Construct(mCause);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mCause;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_TimestampTimelineMarker_h_
|
|
@ -7,9 +7,16 @@
|
|||
EXPORTS.mozilla += [
|
||||
'AutoGlobalTimelineMarker.h',
|
||||
'AutoTimelineMarker.h',
|
||||
'ConsoleTimelineMarker.h',
|
||||
'EventTimelineMarker.h',
|
||||
'JavascriptTimelineMarker.h',
|
||||
'LayerTimelineMarker.h',
|
||||
'ObservedDocShell.h',
|
||||
'RestyleTimelineMarker.h',
|
||||
'TimelineConsumers.h',
|
||||
'TimelineMarker.h',
|
||||
'TimelineMarkerEnums.h',
|
||||
'TimestampTimelineMarker.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "nsContentUtils.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "mozilla/ConsoleTimelineMarker.h"
|
||||
#include "mozilla/TimestampTimelineMarker.h"
|
||||
|
||||
#include "nsIConsoleAPIStorage.h"
|
||||
#include "nsIDOMWindowUtils.h"
|
||||
|
@ -985,59 +987,6 @@ ReifyStack(nsIStackFrame* aStack, nsTArray<ConsoleStackEntry>& aRefiedStack)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class ConsoleTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
ConsoleTimelineMarker(nsDocShell* aDocShell,
|
||||
TracingMetadata aMetaData,
|
||||
const nsAString& aCause)
|
||||
: TimelineMarker(aDocShell, "ConsoleTime", aMetaData, aCause)
|
||||
{
|
||||
if (aMetaData == TRACING_INTERVAL_END) {
|
||||
CaptureStack();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool Equals(const TimelineMarker& aOther) override
|
||||
{
|
||||
if (!TimelineMarker::Equals(aOther)) {
|
||||
return false;
|
||||
}
|
||||
// Console markers must have matching causes as well.
|
||||
return GetCause() == aOther.GetCause();
|
||||
}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx,
|
||||
mozilla::dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
if (GetMetaData() == TRACING_INTERVAL_START) {
|
||||
aMarker.mCauseName.Construct(GetCause());
|
||||
} else {
|
||||
aMarker.mEndStack = GetStack();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class TimestampTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
TimestampTimelineMarker(nsDocShell* aDocShell,
|
||||
TracingMetadata aMetaData,
|
||||
const nsAString& aCause)
|
||||
: TimelineMarker(aDocShell, "TimeStamp", aMetaData, aCause)
|
||||
{
|
||||
MOZ_ASSERT(aMetaData == TRACING_TIMESTAMP);
|
||||
}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx,
|
||||
mozilla::dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
if (!GetCause().IsEmpty()) {
|
||||
aMarker.mCauseName.Construct(GetCause());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Queue a call to a console method. See the CALL_DELAY constant.
|
||||
void
|
||||
Console::Method(JSContext* aCx, MethodName aMethodName,
|
||||
|
@ -1144,8 +1093,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
|
|||
key.init(aCx, jsString);
|
||||
}
|
||||
|
||||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<TimestampTimelineMarker>(docShell, TRACING_TIMESTAMP, key);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<TimestampTimelineMarker>(key);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
}
|
||||
// For `console.time(foo)` and `console.timeEnd(foo)`
|
||||
|
@ -1155,10 +1103,9 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
|
|||
if (jsString) {
|
||||
nsAutoJSString key;
|
||||
if (key.init(aCx, jsString)) {
|
||||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<ConsoleTimelineMarker>(docShell,
|
||||
aMethodName == MethodTime ? TRACING_INTERVAL_START : TRACING_INTERVAL_END,
|
||||
key);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<ConsoleTimelineMarker>(
|
||||
key, aMethodName == MethodTime ? MarkerTracingType::START
|
||||
: MarkerTracingType::END);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,60 +33,8 @@ namespace {
|
|||
StaticRefPtr<BluetoothA2dpManager> sBluetoothA2dpManager;
|
||||
bool sInShutdown = false;
|
||||
static BluetoothA2dpInterface* sBtA2dpInterface;
|
||||
static BluetoothAvrcpInterface* sBtAvrcpInterface;
|
||||
} // namespace
|
||||
|
||||
/*
|
||||
* This function maps attribute id and returns corresponding values
|
||||
*/
|
||||
static void
|
||||
ConvertAttributeString(BluetoothAvrcpMediaAttribute aAttrId,
|
||||
nsAString& aAttrStr)
|
||||
{
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(a2dp);
|
||||
|
||||
switch (aAttrId) {
|
||||
case AVRCP_MEDIA_ATTRIBUTE_TITLE:
|
||||
a2dp->GetTitle(aAttrStr);
|
||||
/*
|
||||
* bluedroid can only send string length AVRC_MAX_ATTR_STR_LEN - 1
|
||||
*/
|
||||
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
|
||||
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
|
||||
BT_WARNING("Truncate media item attribute title, length is over 255");
|
||||
}
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
|
||||
a2dp->GetArtist(aAttrStr);
|
||||
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
|
||||
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
|
||||
BT_WARNING("Truncate media item attribute artist, length is over 255");
|
||||
}
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
|
||||
a2dp->GetAlbum(aAttrStr);
|
||||
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
|
||||
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
|
||||
BT_WARNING("Truncate media item attribute album, length is over 255");
|
||||
}
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM:
|
||||
aAttrStr.AppendInt(a2dp->GetMediaNumber());
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS:
|
||||
aAttrStr.AppendInt(a2dp->GetTotalMediaNumber());
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_GENRE:
|
||||
// TODO: we currently don't support genre from music player
|
||||
aAttrStr.Truncate();
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME:
|
||||
aAttrStr.AppendInt(a2dp->GetDuration());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BluetoothA2dpManager::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
|
@ -111,8 +59,9 @@ BluetoothA2dpManager::BluetoothA2dpManager()
|
|||
void
|
||||
BluetoothA2dpManager::Reset()
|
||||
{
|
||||
ResetA2dp();
|
||||
ResetAvrcp();
|
||||
mA2dpConnected = false;
|
||||
mSinkState = SinkState::SINK_DISCONNECTED;
|
||||
mController = nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -137,42 +86,6 @@ AvStatusToSinkString(BluetoothA2dpConnectionState aState, nsAString& aString)
|
|||
}
|
||||
}
|
||||
|
||||
class BluetoothA2dpManager::InitAvrcpResultHandler final
|
||||
: public BluetoothAvrcpResultHandler
|
||||
{
|
||||
public:
|
||||
InitAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
|
||||
: mRes(aRes)
|
||||
{ }
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
{
|
||||
BT_WARNING("BluetoothAvrcpInterface::Init failed: %d",
|
||||
(int)aStatus);
|
||||
if (mRes) {
|
||||
if (aStatus == STATUS_UNSUPPORTED) {
|
||||
/* Not all versions of Bluedroid support AVRCP. So if the
|
||||
* initialization fails with STATUS_UNSUPPORTED, we still
|
||||
* signal success.
|
||||
*/
|
||||
mRes->Init();
|
||||
} else {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Init() override
|
||||
{
|
||||
if (mRes) {
|
||||
mRes->Init();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||
};
|
||||
|
||||
class BluetoothA2dpManager::InitA2dpResultHandler final
|
||||
: public BluetoothA2dpResultHandler
|
||||
{
|
||||
|
@ -192,20 +105,9 @@ public:
|
|||
|
||||
void Init() override
|
||||
{
|
||||
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
return;
|
||||
if (mRes) {
|
||||
mRes->Init();
|
||||
}
|
||||
|
||||
sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
|
||||
if (NS_WARN_IF(!sBtAvrcpInterface)) {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
|
||||
sBtAvrcpInterface->Init(a2dpManager, new InitAvrcpResultHandler(mRes));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -282,25 +184,6 @@ BluetoothA2dpManager::~BluetoothA2dpManager()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::ResetA2dp()
|
||||
{
|
||||
mA2dpConnected = false;
|
||||
mSinkState = SinkState::SINK_DISCONNECTED;
|
||||
mController = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::ResetAvrcp()
|
||||
{
|
||||
mAvrcpConnected = false;
|
||||
mDuration = 0;
|
||||
mMediaNumber = 0;
|
||||
mTotalMediaCount = 0;
|
||||
mPosition = 0;
|
||||
mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Static functions
|
||||
*/
|
||||
|
@ -344,46 +227,6 @@ BluetoothA2dpManager::Get()
|
|||
return sBluetoothA2dpManager;
|
||||
}
|
||||
|
||||
class BluetoothA2dpManager::CleanupAvrcpResultHandler final
|
||||
: public BluetoothAvrcpResultHandler
|
||||
{
|
||||
public:
|
||||
CleanupAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
|
||||
: mRes(aRes)
|
||||
{ }
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
{
|
||||
BT_WARNING("BluetoothAvrcpInterface::Cleanup failed: %d",
|
||||
(int)aStatus);
|
||||
|
||||
sBtAvrcpInterface = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
if (aStatus == STATUS_UNSUPPORTED) {
|
||||
/* Not all versions of Bluedroid support AVRCP. So if the
|
||||
* cleanup fails with STATUS_UNSUPPORTED, we still signal
|
||||
* success.
|
||||
*/
|
||||
mRes->Deinit();
|
||||
} else {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cleanup() override
|
||||
{
|
||||
sBtAvrcpInterface = nullptr;
|
||||
if (mRes) {
|
||||
mRes->Deinit();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||
};
|
||||
|
||||
class BluetoothA2dpManager::CleanupA2dpResultHandler final
|
||||
: public BluetoothA2dpResultHandler
|
||||
{
|
||||
|
@ -407,12 +250,8 @@ public:
|
|||
void Cleanup() override
|
||||
{
|
||||
sBtA2dpInterface = nullptr;
|
||||
if (sBtAvrcpInterface) {
|
||||
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
|
||||
} else if (mRes) {
|
||||
/* Not all backends support AVRCP. If it's not available
|
||||
* we signal success from here.
|
||||
*/
|
||||
|
||||
if (mRes) {
|
||||
mRes->Deinit();
|
||||
}
|
||||
}
|
||||
|
@ -432,15 +271,10 @@ public:
|
|||
NS_IMETHOD Run() override
|
||||
{
|
||||
sBtA2dpInterface = nullptr;
|
||||
if (sBtAvrcpInterface) {
|
||||
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
|
||||
} else if (mRes) {
|
||||
/* Not all backends support AVRCP. If it's not available
|
||||
* we signal success from here.
|
||||
*/
|
||||
|
||||
if (mRes) {
|
||||
mRes->Deinit();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -784,233 +618,7 @@ BluetoothA2dpManager::IsConnected()
|
|||
}
|
||||
|
||||
/*
|
||||
* In bluedroid stack case, there is no interface to know exactly
|
||||
* avrcp connection status. All connection are managed by bluedroid stack.
|
||||
*/
|
||||
void
|
||||
BluetoothA2dpManager::SetAvrcpConnected(bool aConnected)
|
||||
{
|
||||
mAvrcpConnected = aConnected;
|
||||
if (!aConnected) {
|
||||
ResetAvrcp();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothA2dpManager::IsAvrcpConnected()
|
||||
{
|
||||
return mAvrcpConnected;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function only updates meta data in BluetoothA2dpManager
|
||||
* Send "Get Element Attributes response" in AvrcpGetElementAttrCallback
|
||||
*/
|
||||
void
|
||||
BluetoothA2dpManager::UpdateMetaData(const nsAString& aTitle,
|
||||
const nsAString& aArtist,
|
||||
const nsAString& aAlbum,
|
||||
uint64_t aMediaNumber,
|
||||
uint64_t aTotalMediaCount,
|
||||
uint32_t aDuration)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
|
||||
|
||||
// Send track changed and position changed if track num is not the same.
|
||||
// See also AVRCP 1.3 Spec 5.4.2
|
||||
if (mMediaNumber != aMediaNumber &&
|
||||
mTrackChangedNotifyType == AVRCP_NTF_INTERIM) {
|
||||
BluetoothAvrcpNotificationParam param;
|
||||
// convert to network big endian format
|
||||
// since track stores as uint8[8]
|
||||
// 56 = 8 * (AVRCP_UID_SIZE -1)
|
||||
for (int i = 0; i < AVRCP_UID_SIZE; ++i) {
|
||||
param.mTrack[i] = (aMediaNumber >> (56 - 8 * i));
|
||||
}
|
||||
mTrackChangedNotifyType = AVRCP_NTF_CHANGED;
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_TRACK_CHANGE,
|
||||
AVRCP_NTF_CHANGED,
|
||||
param, nullptr);
|
||||
if (mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
|
||||
param.mSongPos = mPosition;
|
||||
// EVENT_PLAYBACK_POS_CHANGED shall be notified if changed current track
|
||||
mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
|
||||
AVRCP_NTF_CHANGED,
|
||||
param, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
mTitle.Assign(aTitle);
|
||||
mArtist.Assign(aArtist);
|
||||
mAlbum.Assign(aAlbum);
|
||||
mMediaNumber = aMediaNumber;
|
||||
mTotalMediaCount = aTotalMediaCount;
|
||||
mDuration = aDuration;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is to reply AvrcpGetPlayStatusCallback (play-status-request)
|
||||
* from media player application (Gaia side)
|
||||
*/
|
||||
void
|
||||
BluetoothA2dpManager::UpdatePlayStatus(uint32_t aDuration,
|
||||
uint32_t aPosition,
|
||||
ControlPlayStatus aPlayStatus)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
|
||||
// always update playstatus first
|
||||
sBtAvrcpInterface->GetPlayStatusRsp(aPlayStatus, aDuration,
|
||||
aPosition, nullptr);
|
||||
// when play status changed, send both play status and position
|
||||
if (mPlayStatus != aPlayStatus &&
|
||||
mPlayStatusChangedNotifyType == AVRCP_NTF_INTERIM) {
|
||||
BluetoothAvrcpNotificationParam param;
|
||||
param.mPlayStatus = aPlayStatus;
|
||||
mPlayStatusChangedNotifyType = AVRCP_NTF_CHANGED;
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_STATUS_CHANGED,
|
||||
AVRCP_NTF_CHANGED,
|
||||
param, nullptr);
|
||||
}
|
||||
|
||||
if (mPosition != aPosition &&
|
||||
mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
|
||||
BluetoothAvrcpNotificationParam param;
|
||||
param.mSongPos = aPosition;
|
||||
mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
|
||||
AVRCP_NTF_CHANGED,
|
||||
param, nullptr);
|
||||
}
|
||||
|
||||
mDuration = aDuration;
|
||||
mPosition = aPosition;
|
||||
mPlayStatus = aPlayStatus;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles RegisterNotification request from
|
||||
* AvrcpRegisterNotificationCallback, which updates current
|
||||
* track/status/position status in the INTERRIM response.
|
||||
*
|
||||
* aParam is only valid when position changed
|
||||
*/
|
||||
void
|
||||
BluetoothA2dpManager::UpdateRegisterNotification(BluetoothAvrcpEvent aEvent,
|
||||
uint32_t aParam)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
|
||||
|
||||
BluetoothAvrcpNotificationParam param;
|
||||
|
||||
switch (aEvent) {
|
||||
case AVRCP_EVENT_PLAY_STATUS_CHANGED:
|
||||
mPlayStatusChangedNotifyType = AVRCP_NTF_INTERIM;
|
||||
param.mPlayStatus = mPlayStatus;
|
||||
break;
|
||||
case AVRCP_EVENT_TRACK_CHANGE:
|
||||
// In AVRCP 1.3 and 1.4, the identifier parameter of EVENT_TRACK_CHANGED
|
||||
// is different.
|
||||
// AVRCP 1.4: If no track is selected, we shall return 0xFFFFFFFFFFFFFFFF,
|
||||
// otherwise return 0x0 in the INTERRIM response. The expanded text in
|
||||
// version 1.4 is to allow for new UID feature. As for AVRCP 1.3, we shall
|
||||
// return 0xFFFFFFFF. Since PTS enforces to check this part to comply with
|
||||
// the most updated spec.
|
||||
mTrackChangedNotifyType = AVRCP_NTF_INTERIM;
|
||||
// needs to convert to network big endian format since track stores
|
||||
// as uint8[8]. 56 = 8 * (BTRC_UID_SIZE -1).
|
||||
for (int index = 0; index < AVRCP_UID_SIZE; ++index) {
|
||||
// We cannot easily check if a track is selected, so whenever A2DP is
|
||||
// streaming, we assume a track is selected.
|
||||
if (mSinkState == BluetoothA2dpManager::SinkState::SINK_PLAYING) {
|
||||
param.mTrack[index] = 0x0;
|
||||
} else {
|
||||
param.mTrack[index] = 0xFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AVRCP_EVENT_PLAY_POS_CHANGED:
|
||||
// If no track is selected, return 0xFFFFFFFF in the INTERIM response
|
||||
mPlayPosChangedNotifyType = AVRCP_NTF_INTERIM;
|
||||
if (mSinkState == BluetoothA2dpManager::SinkState::SINK_PLAYING) {
|
||||
param.mSongPos = mPosition;
|
||||
} else {
|
||||
param.mSongPos = 0xFFFFFFFF;
|
||||
}
|
||||
mPlaybackInterval = aParam;
|
||||
break;
|
||||
case AVRCP_EVENT_APP_SETTINGS_CHANGED:
|
||||
mAppSettingsChangedNotifyType = AVRCP_NTF_INTERIM;
|
||||
param.mNumAttr = 2;
|
||||
param.mIds[0] = AVRCP_PLAYER_ATTRIBUTE_REPEAT;
|
||||
param.mValues[0] = AVRCP_PLAYER_VAL_OFF_REPEAT;
|
||||
param.mIds[1] = AVRCP_PLAYER_ATTRIBUTE_SHUFFLE;
|
||||
param.mValues[1] = AVRCP_PLAYER_VAL_OFF_SHUFFLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(aEvent, AVRCP_NTF_INTERIM,
|
||||
param, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::GetAlbum(nsAString& aAlbum)
|
||||
{
|
||||
aAlbum.Assign(mAlbum);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BluetoothA2dpManager::GetDuration()
|
||||
{
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
ControlPlayStatus
|
||||
BluetoothA2dpManager::GetPlayStatus()
|
||||
{
|
||||
return mPlayStatus;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BluetoothA2dpManager::GetPosition()
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
BluetoothA2dpManager::GetMediaNumber()
|
||||
{
|
||||
return mMediaNumber;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
BluetoothA2dpManager::GetTotalMediaNumber()
|
||||
{
|
||||
return mTotalMediaCount;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::GetTitle(nsAString& aTitle)
|
||||
{
|
||||
aTitle.Assign(mTitle);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::GetArtist(nsAString& aArtist)
|
||||
{
|
||||
aArtist.Assign(mArtist);
|
||||
}
|
||||
|
||||
/*
|
||||
* A2DP Notifications
|
||||
* Notifications
|
||||
*/
|
||||
|
||||
void
|
||||
|
@ -1054,179 +662,4 @@ BluetoothA2dpManager::AudioStateNotification(BluetoothA2dpAudioState aState,
|
|||
nsString(aBdAddr), props));
|
||||
}
|
||||
|
||||
/*
|
||||
* AVRCP Notifications
|
||||
*/
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::GetPlayStatusNotification()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
if (!bs) {
|
||||
return;
|
||||
}
|
||||
|
||||
bs->DistributeSignal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER));
|
||||
}
|
||||
|
||||
/* Player application settings is optional for AVRCP 1.3. B2G
|
||||
* currently does not support player-application-setting related
|
||||
* functionality.
|
||||
*/
|
||||
void
|
||||
BluetoothA2dpManager::ListPlayerAppAttrNotification()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::ListPlayerAppValuesNotification(
|
||||
BluetoothAvrcpPlayerAttribute aAttrId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::GetPlayerAppValueNotification(
|
||||
uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::GetPlayerAppAttrsTextNotification(
|
||||
uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::GetPlayerAppValuesTextNotification(
|
||||
uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::SetPlayerAppValueNotification(
|
||||
const BluetoothAvrcpPlayerSettings& aSettings)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
/* This method returns element attributes, which are requested from
|
||||
* CT. Unlike BlueZ it calls only UpdateMetaData. Bluedroid does not cache
|
||||
* meta-data information, but instead uses |GetElementAttrNotifications|
|
||||
* and |GetElementAttrRsp| request them.
|
||||
*/
|
||||
void
|
||||
BluetoothA2dpManager::GetElementAttrNotification(
|
||||
uint8_t aNumAttrs, const BluetoothAvrcpMediaAttribute* aAttrs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsAutoArrayPtr<BluetoothAvrcpElementAttribute> attrs(
|
||||
new BluetoothAvrcpElementAttribute[aNumAttrs]);
|
||||
|
||||
for (uint8_t i = 0; i < aNumAttrs; ++i) {
|
||||
attrs[i].mId = aAttrs[i];
|
||||
ConvertAttributeString(
|
||||
static_cast<BluetoothAvrcpMediaAttribute>(attrs[i].mId),
|
||||
attrs[i].mValue);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(sBtAvrcpInterface);
|
||||
sBtAvrcpInterface->GetElementAttrRsp(aNumAttrs, attrs, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::RegisterNotificationNotification(
|
||||
BluetoothAvrcpEvent aEvent, uint32_t aParam)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
if (!a2dp) {
|
||||
return;
|
||||
}
|
||||
|
||||
a2dp->UpdateRegisterNotification(aEvent, aParam);
|
||||
}
|
||||
|
||||
/* This method is used to get CT features from the Feature Bit Mask. If
|
||||
* Advanced Control Player bit is set, the CT supports volume sync (absolute
|
||||
* volume feature). If Browsing bit is set, AVRCP 1.4 Browse feature will be
|
||||
* supported.
|
||||
*/
|
||||
void
|
||||
BluetoothA2dpManager::RemoteFeatureNotification(
|
||||
const nsAString& aBdAddr, unsigned long aFeatures)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP 1.4 absolute volume/browse
|
||||
}
|
||||
|
||||
/* This method is used to get notifications about volume changes on the
|
||||
* remote car kit (if it supports AVRCP 1.4), not notification from phone.
|
||||
*/
|
||||
void
|
||||
BluetoothA2dpManager::VolumeChangeNotification(uint8_t aVolume,
|
||||
uint8_t aCType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP 1.4 absolute volume/browse
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::PassthroughCmdNotification(int aId, int aKeyState)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Fast-forward and rewind key events won't be generated from bluedroid
|
||||
// stack after ANDROID_VERSION > 18, but via passthrough callback.
|
||||
nsAutoString name;
|
||||
NS_ENSURE_TRUE_VOID(aKeyState == AVRC_KEY_PRESS_STATE ||
|
||||
aKeyState == AVRC_KEY_RELEASE_STATE);
|
||||
switch (aId) {
|
||||
case AVRC_ID_FAST_FOR:
|
||||
if (aKeyState == AVRC_KEY_PRESS_STATE) {
|
||||
name.AssignLiteral("media-fast-forward-button-press");
|
||||
} else {
|
||||
name.AssignLiteral("media-fast-forward-button-release");
|
||||
}
|
||||
break;
|
||||
case AVRC_ID_REWIND:
|
||||
if (aKeyState == AVRC_KEY_PRESS_STATE) {
|
||||
name.AssignLiteral("media-rewind-button-press");
|
||||
} else {
|
||||
name.AssignLiteral("media-rewind-button-release");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BT_WARNING("Unable to handle the unknown PassThrough command %d", aId);
|
||||
return;
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_STRING(type, "media-button");
|
||||
BroadcastSystemMessage(type, BluetoothValue(name));
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(BluetoothA2dpManager, nsIObserver)
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
class BluetoothA2dpManager : public BluetoothProfileManagerBase
|
||||
, public BluetoothA2dpNotificationHandler
|
||||
, public BluetoothAvrcpNotificationHandler
|
||||
{
|
||||
public:
|
||||
BT_DECL_PROFILE_MGR_BASE
|
||||
|
@ -42,27 +41,6 @@ public:
|
|||
// A2DP-specific functions
|
||||
void HandleSinkPropertyChanged(const BluetoothSignal& aSignal);
|
||||
|
||||
// AVRCP-specific functions
|
||||
void SetAvrcpConnected(bool aConnected);
|
||||
bool IsAvrcpConnected();
|
||||
void UpdateMetaData(const nsAString& aTitle,
|
||||
const nsAString& aArtist,
|
||||
const nsAString& aAlbum,
|
||||
uint64_t aMediaNumber,
|
||||
uint64_t aTotalMediaCount,
|
||||
uint32_t aDuration);
|
||||
void UpdatePlayStatus(uint32_t aDuration,
|
||||
uint32_t aPosition,
|
||||
ControlPlayStatus aPlayStatus);
|
||||
void UpdateRegisterNotification(BluetoothAvrcpEvent aEvent, uint32_t aParam);
|
||||
void GetAlbum(nsAString& aAlbum);
|
||||
uint32_t GetDuration();
|
||||
ControlPlayStatus GetPlayStatus();
|
||||
uint32_t GetPosition();
|
||||
uint64_t GetMediaNumber();
|
||||
uint64_t GetTotalMediaNumber();
|
||||
void GetTitle(nsAString& aTitle);
|
||||
void GetArtist(nsAString& aArtist);
|
||||
void HandleBackendError();
|
||||
|
||||
protected:
|
||||
|
@ -71,16 +49,12 @@ protected:
|
|||
private:
|
||||
class CleanupA2dpResultHandler;
|
||||
class CleanupA2dpResultHandlerRunnable;
|
||||
class CleanupAvrcpResultHandler;
|
||||
class ConnectResultHandler;
|
||||
class DisconnectResultHandler;
|
||||
class InitA2dpResultHandler;
|
||||
class InitAvrcpResultHandler;
|
||||
class OnErrorProfileResultHandlerRunnable;
|
||||
|
||||
BluetoothA2dpManager();
|
||||
void ResetA2dp();
|
||||
void ResetAvrcp();
|
||||
|
||||
void HandleShutdown();
|
||||
void NotifyConnectionStatusChanged();
|
||||
|
@ -90,79 +64,12 @@ private:
|
|||
void AudioStateNotification(BluetoothA2dpAudioState aState,
|
||||
const nsAString& aBdAddr) override;
|
||||
|
||||
void GetPlayStatusNotification() override;
|
||||
|
||||
void ListPlayerAppAttrNotification() override;
|
||||
|
||||
void ListPlayerAppValuesNotification(
|
||||
BluetoothAvrcpPlayerAttribute aAttrId) override;
|
||||
|
||||
void GetPlayerAppValueNotification(
|
||||
uint8_t aNumAttrs,
|
||||
const BluetoothAvrcpPlayerAttribute* aAttrs) override;
|
||||
|
||||
void GetPlayerAppAttrsTextNotification(
|
||||
uint8_t aNumAttrs,
|
||||
const BluetoothAvrcpPlayerAttribute* aAttrs) override;
|
||||
|
||||
void GetPlayerAppValuesTextNotification(
|
||||
uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues) override;
|
||||
|
||||
void SetPlayerAppValueNotification(
|
||||
const BluetoothAvrcpPlayerSettings& aSettings) override;
|
||||
|
||||
void GetElementAttrNotification(
|
||||
uint8_t aNumAttrs,
|
||||
const BluetoothAvrcpMediaAttribute* aAttrs) override;
|
||||
|
||||
void RegisterNotificationNotification(
|
||||
BluetoothAvrcpEvent aEvent, uint32_t aParam) override;
|
||||
|
||||
void RemoteFeatureNotification(
|
||||
const nsAString& aBdAddr, unsigned long aFeatures) override;
|
||||
|
||||
void VolumeChangeNotification(uint8_t aVolume, uint8_t aCType) override;
|
||||
|
||||
void PassthroughCmdNotification(int aId, int aKeyState) override;
|
||||
|
||||
nsString mDeviceAddress;
|
||||
nsRefPtr<BluetoothProfileController> mController;
|
||||
|
||||
// A2DP data member
|
||||
bool mA2dpConnected;
|
||||
SinkState mSinkState;
|
||||
|
||||
// AVRCP data member
|
||||
bool mAvrcpConnected;
|
||||
nsString mAlbum;
|
||||
nsString mArtist;
|
||||
nsString mTitle;
|
||||
uint32_t mDuration;
|
||||
uint64_t mMediaNumber;
|
||||
uint64_t mTotalMediaCount;
|
||||
uint32_t mPosition;
|
||||
/*
|
||||
* mPlaybackInterval specifies the time interval (in seconds) at which
|
||||
* the change in playback position will be notified. If the song is being
|
||||
* forwarded / rewound, a notification will be received whenever the playback
|
||||
* position will change by this value.
|
||||
*/
|
||||
uint32_t mPlaybackInterval;
|
||||
ControlPlayStatus mPlayStatus;
|
||||
/*
|
||||
* Notification types: 1. INTERIM 2. CHANGED
|
||||
* 1. The initial response to this Notify command shall be an INTERIM
|
||||
* response with current status.
|
||||
* 2. The following response shall be a CHANGED response with the updated
|
||||
* status.
|
||||
* mPlayStatusChangedNotifType, mTrackChangedNotifType,
|
||||
* mPlayPosChangedNotifType represents current RegisterNotification
|
||||
* notification type.
|
||||
*/
|
||||
BluetoothAvrcpNotification mPlayStatusChangedNotifyType;
|
||||
BluetoothAvrcpNotification mTrackChangedNotifyType;
|
||||
BluetoothAvrcpNotification mPlayPosChangedNotifyType;
|
||||
BluetoothAvrcpNotification mAppSettingsChangedNotifyType;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
|
|
@ -0,0 +1,816 @@
|
|||
/* -*- 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 "base/basictypes.h"
|
||||
|
||||
#include "BluetoothAvrcpManager.h"
|
||||
#include "BluetoothCommon.h"
|
||||
#include "BluetoothService.h"
|
||||
#include "BluetoothSocket.h"
|
||||
#include "BluetoothUtils.h"
|
||||
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
// AVRC_ID op code follows bluedroid avrc_defs.h
|
||||
#define AVRC_ID_REWIND 0x48
|
||||
#define AVRC_ID_FAST_FOR 0x49
|
||||
#define AVRC_KEY_PRESS_STATE 1
|
||||
#define AVRC_KEY_RELEASE_STATE 0
|
||||
// bluedroid bt_rc.h
|
||||
#define AVRC_MAX_ATTR_STR_LEN 255
|
||||
|
||||
namespace {
|
||||
StaticRefPtr<BluetoothAvrcpManager> sBluetoothAvrcpManager;
|
||||
bool sInShutdown = false;
|
||||
static BluetoothAvrcpInterface* sBtAvrcpInterface;
|
||||
} // namespace
|
||||
|
||||
/*
|
||||
* This function maps attribute id and returns corresponding values
|
||||
*/
|
||||
static void
|
||||
ConvertAttributeString(BluetoothAvrcpMediaAttribute aAttrId,
|
||||
nsAString& aAttrStr)
|
||||
{
|
||||
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(avrcp);
|
||||
|
||||
switch (aAttrId) {
|
||||
case AVRCP_MEDIA_ATTRIBUTE_TITLE:
|
||||
avrcp->GetTitle(aAttrStr);
|
||||
/*
|
||||
* bluedroid can only send string length AVRC_MAX_ATTR_STR_LEN - 1
|
||||
*/
|
||||
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
|
||||
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
|
||||
BT_WARNING("Truncate media item attribute title, length is over 255");
|
||||
}
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
|
||||
avrcp->GetArtist(aAttrStr);
|
||||
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
|
||||
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
|
||||
BT_WARNING("Truncate media item attribute artist, length is over 255");
|
||||
}
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
|
||||
avrcp->GetAlbum(aAttrStr);
|
||||
if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
|
||||
aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
|
||||
BT_WARNING("Truncate media item attribute album, length is over 255");
|
||||
}
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM:
|
||||
aAttrStr.AppendInt(avrcp->GetMediaNumber());
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS:
|
||||
aAttrStr.AppendInt(avrcp->GetTotalMediaNumber());
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_GENRE:
|
||||
// TODO: we currently don't support genre from music player
|
||||
aAttrStr.Truncate();
|
||||
break;
|
||||
case AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME:
|
||||
aAttrStr.AppendInt(avrcp->GetDuration());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BluetoothAvrcpManager::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(sBluetoothAvrcpManager);
|
||||
|
||||
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
||||
HandleShutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "BluetoothAvrcpManager got unexpected topic!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
BluetoothAvrcpManager::BluetoothAvrcpManager()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::Reset()
|
||||
{
|
||||
mAvrcpConnected = false;
|
||||
mDuration = 0;
|
||||
mMediaNumber = 0;
|
||||
mTotalMediaCount = 0;
|
||||
mPosition = 0;
|
||||
mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
|
||||
}
|
||||
|
||||
class BluetoothAvrcpManager::InitAvrcpResultHandler final
|
||||
: public BluetoothAvrcpResultHandler
|
||||
{
|
||||
public:
|
||||
InitAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
|
||||
: mRes(aRes)
|
||||
{ }
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
{
|
||||
BT_WARNING("BluetoothAvrcpInterface::Init failed: %d",
|
||||
(int)aStatus);
|
||||
if (mRes) {
|
||||
if (aStatus == STATUS_UNSUPPORTED) {
|
||||
/* Not all versions of Bluedroid support AVRCP. So if the
|
||||
* initialization fails with STATUS_UNSUPPORTED, we still
|
||||
* signal success.
|
||||
*/
|
||||
mRes->Init();
|
||||
} else {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Init() override
|
||||
{
|
||||
if (mRes) {
|
||||
mRes->Init();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||
};
|
||||
|
||||
class BluetoothAvrcpManager::OnErrorProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
{
|
||||
public:
|
||||
OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
nsresult aRv)
|
||||
: mRes(aRes)
|
||||
, mRv(aRv)
|
||||
{
|
||||
MOZ_ASSERT(mRes);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mRes->OnError(mRv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||
nsresult mRv;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function will be only called when Bluetooth is turning on.
|
||||
*/
|
||||
// static
|
||||
void
|
||||
BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no HFP interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
nsRefPtr<nsRunnable> r =
|
||||
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
|
||||
if (NS_WARN_IF(!sBtAvrcpInterface)) {
|
||||
// If there's no AVRCP interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
nsRefPtr<nsRunnable> r =
|
||||
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BluetoothAvrcpManager* avrcpManager = BluetoothAvrcpManager::Get();
|
||||
sBtAvrcpInterface->Init(avrcpManager, new InitAvrcpResultHandler(aRes));
|
||||
}
|
||||
|
||||
BluetoothAvrcpManager::~BluetoothAvrcpManager()
|
||||
{
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Static functions
|
||||
*/
|
||||
|
||||
//static
|
||||
BluetoothAvrcpManager*
|
||||
BluetoothAvrcpManager::Get()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// If sBluetoothAvrcpManager already exists, exit early
|
||||
if (sBluetoothAvrcpManager) {
|
||||
return sBluetoothAvrcpManager;
|
||||
}
|
||||
|
||||
// If we're in shutdown, don't create a new instance
|
||||
NS_ENSURE_FALSE(sInShutdown, nullptr);
|
||||
|
||||
// Create a new instance, register, and return
|
||||
BluetoothAvrcpManager* manager = new BluetoothAvrcpManager();
|
||||
sBluetoothAvrcpManager = manager;
|
||||
return sBluetoothAvrcpManager;
|
||||
}
|
||||
|
||||
class BluetoothAvrcpManager::CleanupAvrcpResultHandler final
|
||||
: public BluetoothAvrcpResultHandler
|
||||
{
|
||||
public:
|
||||
CleanupAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
|
||||
: mRes(aRes)
|
||||
{ }
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
{
|
||||
BT_WARNING("BluetoothAvrcpInterface::Cleanup failed: %d",
|
||||
(int)aStatus);
|
||||
|
||||
sBtAvrcpInterface = nullptr;
|
||||
|
||||
if (mRes) {
|
||||
if (aStatus == STATUS_UNSUPPORTED) {
|
||||
/* Not all versions of Bluedroid support AVRCP. So if the
|
||||
* cleanup fails with STATUS_UNSUPPORTED, we still signal
|
||||
* success.
|
||||
*/
|
||||
mRes->Deinit();
|
||||
} else {
|
||||
mRes->OnError(NS_ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cleanup() override
|
||||
{
|
||||
sBtAvrcpInterface = nullptr;
|
||||
if (mRes) {
|
||||
mRes->Deinit();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||
};
|
||||
|
||||
class BluetoothAvrcpManager::CleanupAvrcpResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
{
|
||||
public:
|
||||
CleanupAvrcpResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
|
||||
: mRes(aRes)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
sBtAvrcpInterface = nullptr;
|
||||
if (sBtAvrcpInterface) {
|
||||
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
|
||||
} else if (mRes) {
|
||||
/* Not all backends support AVRCP. If it's not available
|
||||
* we signal success from here.
|
||||
*/
|
||||
mRes->Deinit();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||
};
|
||||
|
||||
// static
|
||||
void
|
||||
BluetoothAvrcpManager::DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sBtAvrcpInterface) {
|
||||
sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(aRes));
|
||||
} else if (aRes) {
|
||||
// We dispatch a runnable here to make the profile resource handler
|
||||
// behave as if A2DP was initialized.
|
||||
nsRefPtr<nsRunnable> r = new CleanupAvrcpResultHandlerRunnable(aRes);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::HandleShutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
sInShutdown = true;
|
||||
Disconnect(nullptr);
|
||||
sBluetoothAvrcpManager = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::Connect(const nsAString& aDeviceAddress,
|
||||
BluetoothProfileController* aController)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
|
||||
MOZ_ASSERT(aController);
|
||||
|
||||
// AVRCP doesn't require connecting. We just set the remote address here.
|
||||
mDeviceAddress = aDeviceAddress;
|
||||
SetConnected(true);
|
||||
OnConnect(EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::Disconnect(BluetoothProfileController* aController)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mController);
|
||||
|
||||
mDeviceAddress.Truncate();
|
||||
SetConnected(false);
|
||||
OnDisconnect(EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::OnConnect(const nsAString& aErrorStr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
/**
|
||||
* On the one hand, notify the controller that we've done for outbound
|
||||
* connections. On the other hand, we do nothing for inbound connections.
|
||||
*/
|
||||
NS_ENSURE_TRUE_VOID(mController);
|
||||
|
||||
nsRefPtr<BluetoothProfileController> controller = mController.forget();
|
||||
controller->NotifyCompletion(aErrorStr);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::OnDisconnect(const nsAString& aErrorStr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
/**
|
||||
* On the one hand, notify the controller that we've done for outbound
|
||||
* connections. On the other hand, we do nothing for inbound connections.
|
||||
*/
|
||||
NS_ENSURE_TRUE_VOID(mController);
|
||||
|
||||
nsRefPtr<BluetoothProfileController> controller = mController.forget();
|
||||
controller->NotifyCompletion(aErrorStr);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
|
||||
const nsAString& aServiceUuid,
|
||||
int aChannel)
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetAddress(nsAString& aDeviceAddress)
|
||||
{
|
||||
aDeviceAddress = mDeviceAddress;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothAvrcpManager::IsConnected()
|
||||
{
|
||||
return mAvrcpConnected;
|
||||
}
|
||||
|
||||
/*
|
||||
* In bluedroid stack case, there is no interface to know exactly
|
||||
* avrcp connection status. All connection are managed by bluedroid stack.
|
||||
*/
|
||||
void
|
||||
BluetoothAvrcpManager::SetConnected(bool aConnected)
|
||||
{
|
||||
mAvrcpConnected = aConnected;
|
||||
if (!aConnected) {
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function only updates meta data in BluetoothAvrcpManager. Send
|
||||
* "Get Element Attributes response" in AvrcpGetElementAttrCallback
|
||||
*/
|
||||
void
|
||||
BluetoothAvrcpManager::UpdateMetaData(const nsAString& aTitle,
|
||||
const nsAString& aArtist,
|
||||
const nsAString& aAlbum,
|
||||
uint64_t aMediaNumber,
|
||||
uint64_t aTotalMediaCount,
|
||||
uint32_t aDuration)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
|
||||
|
||||
// Send track changed and position changed if track num is not the same.
|
||||
// See also AVRCP 1.3 Spec 5.4.2
|
||||
if (mMediaNumber != aMediaNumber &&
|
||||
mTrackChangedNotifyType == AVRCP_NTF_INTERIM) {
|
||||
BluetoothAvrcpNotificationParam param;
|
||||
// convert to network big endian format
|
||||
// since track stores as uint8[8]
|
||||
// 56 = 8 * (AVRCP_UID_SIZE -1)
|
||||
for (int i = 0; i < AVRCP_UID_SIZE; ++i) {
|
||||
param.mTrack[i] = (aMediaNumber >> (56 - 8 * i));
|
||||
}
|
||||
mTrackChangedNotifyType = AVRCP_NTF_CHANGED;
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_TRACK_CHANGE,
|
||||
AVRCP_NTF_CHANGED,
|
||||
param, nullptr);
|
||||
if (mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
|
||||
param.mSongPos = mPosition;
|
||||
// EVENT_PLAYBACK_POS_CHANGED shall be notified if changed current track
|
||||
mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
|
||||
AVRCP_NTF_CHANGED,
|
||||
param, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
mTitle.Assign(aTitle);
|
||||
mArtist.Assign(aArtist);
|
||||
mAlbum.Assign(aAlbum);
|
||||
mMediaNumber = aMediaNumber;
|
||||
mTotalMediaCount = aTotalMediaCount;
|
||||
mDuration = aDuration;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is to reply AvrcpGetPlayStatusCallback (play-status-request)
|
||||
* from media player application (Gaia side)
|
||||
*/
|
||||
void
|
||||
BluetoothAvrcpManager::UpdatePlayStatus(uint32_t aDuration,
|
||||
uint32_t aPosition,
|
||||
ControlPlayStatus aPlayStatus)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
|
||||
// always update playstatus first
|
||||
sBtAvrcpInterface->GetPlayStatusRsp(aPlayStatus, aDuration,
|
||||
aPosition, nullptr);
|
||||
// when play status changed, send both play status and position
|
||||
if (mPlayStatus != aPlayStatus &&
|
||||
mPlayStatusChangedNotifyType == AVRCP_NTF_INTERIM) {
|
||||
BluetoothAvrcpNotificationParam param;
|
||||
param.mPlayStatus = aPlayStatus;
|
||||
mPlayStatusChangedNotifyType = AVRCP_NTF_CHANGED;
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_STATUS_CHANGED,
|
||||
AVRCP_NTF_CHANGED,
|
||||
param, nullptr);
|
||||
}
|
||||
|
||||
if (mPosition != aPosition &&
|
||||
mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
|
||||
BluetoothAvrcpNotificationParam param;
|
||||
param.mSongPos = aPosition;
|
||||
mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
|
||||
AVRCP_NTF_CHANGED,
|
||||
param, nullptr);
|
||||
}
|
||||
|
||||
mDuration = aDuration;
|
||||
mPosition = aPosition;
|
||||
mPlayStatus = aPlayStatus;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles RegisterNotification request from
|
||||
* AvrcpRegisterNotificationCallback, which updates current
|
||||
* track/status/position status in the INTERRIM response.
|
||||
*
|
||||
* aParam is only valid when position changed
|
||||
*/
|
||||
void
|
||||
BluetoothAvrcpManager::UpdateRegisterNotification(BluetoothAvrcpEvent aEvent,
|
||||
uint32_t aParam)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
|
||||
|
||||
BluetoothAvrcpNotificationParam param;
|
||||
|
||||
switch (aEvent) {
|
||||
case AVRCP_EVENT_PLAY_STATUS_CHANGED:
|
||||
mPlayStatusChangedNotifyType = AVRCP_NTF_INTERIM;
|
||||
param.mPlayStatus = mPlayStatus;
|
||||
break;
|
||||
case AVRCP_EVENT_TRACK_CHANGE:
|
||||
// In AVRCP 1.3 and 1.4, the identifier parameter of EVENT_TRACK_CHANGED
|
||||
// is different.
|
||||
// AVRCP 1.4: If no track is selected, we shall return 0xFFFFFFFFFFFFFFFF,
|
||||
// otherwise return 0x0 in the INTERRIM response. The expanded text in
|
||||
// version 1.4 is to allow for new UID feature. As for AVRCP 1.3, we shall
|
||||
// return 0xFFFFFFFF. Since PTS enforces to check this part to comply with
|
||||
// the most updated spec.
|
||||
mTrackChangedNotifyType = AVRCP_NTF_INTERIM;
|
||||
// needs to convert to network big endian format since track stores
|
||||
// as uint8[8]. 56 = 8 * (BTRC_UID_SIZE -1).
|
||||
for (int index = 0; index < AVRCP_UID_SIZE; ++index) {
|
||||
// We cannot easily check if a track is selected, so whenever A2DP is
|
||||
// streaming, we assume a track is selected.
|
||||
if (mPlayStatus == ControlPlayStatus::PLAYSTATUS_PLAYING) {
|
||||
param.mTrack[index] = 0x0;
|
||||
} else {
|
||||
param.mTrack[index] = 0xFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AVRCP_EVENT_PLAY_POS_CHANGED:
|
||||
// If no track is selected, return 0xFFFFFFFF in the INTERIM response
|
||||
mPlayPosChangedNotifyType = AVRCP_NTF_INTERIM;
|
||||
if (mPlayStatus == ControlPlayStatus::PLAYSTATUS_PLAYING) {
|
||||
param.mSongPos = mPosition;
|
||||
} else {
|
||||
param.mSongPos = 0xFFFFFFFF;
|
||||
}
|
||||
mPlaybackInterval = aParam;
|
||||
break;
|
||||
case AVRCP_EVENT_APP_SETTINGS_CHANGED:
|
||||
mAppSettingsChangedNotifyType = AVRCP_NTF_INTERIM;
|
||||
param.mNumAttr = 2;
|
||||
param.mIds[0] = AVRCP_PLAYER_ATTRIBUTE_REPEAT;
|
||||
param.mValues[0] = AVRCP_PLAYER_VAL_OFF_REPEAT;
|
||||
param.mIds[1] = AVRCP_PLAYER_ATTRIBUTE_SHUFFLE;
|
||||
param.mValues[1] = AVRCP_PLAYER_VAL_OFF_SHUFFLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sBtAvrcpInterface->RegisterNotificationRsp(aEvent, AVRCP_NTF_INTERIM,
|
||||
param, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetAlbum(nsAString& aAlbum)
|
||||
{
|
||||
aAlbum.Assign(mAlbum);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BluetoothAvrcpManager::GetDuration()
|
||||
{
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
ControlPlayStatus
|
||||
BluetoothAvrcpManager::GetPlayStatus()
|
||||
{
|
||||
return mPlayStatus;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BluetoothAvrcpManager::GetPosition()
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
BluetoothAvrcpManager::GetMediaNumber()
|
||||
{
|
||||
return mMediaNumber;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
BluetoothAvrcpManager::GetTotalMediaNumber()
|
||||
{
|
||||
return mTotalMediaCount;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetTitle(nsAString& aTitle)
|
||||
{
|
||||
aTitle.Assign(mTitle);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetArtist(nsAString& aArtist)
|
||||
{
|
||||
aArtist.Assign(mArtist);
|
||||
}
|
||||
|
||||
/*
|
||||
* Notifications
|
||||
*/
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetPlayStatusNotification()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
if (!bs) {
|
||||
return;
|
||||
}
|
||||
|
||||
bs->DistributeSignal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER));
|
||||
}
|
||||
|
||||
/* Player application settings is optional for AVRCP 1.3. B2G
|
||||
* currently does not support player-application-setting related
|
||||
* functionality.
|
||||
*/
|
||||
void
|
||||
BluetoothAvrcpManager::ListPlayerAppAttrNotification()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::ListPlayerAppValuesNotification(
|
||||
BluetoothAvrcpPlayerAttribute aAttrId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetPlayerAppValueNotification(
|
||||
uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetPlayerAppAttrsTextNotification(
|
||||
uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetPlayerAppValuesTextNotification(
|
||||
uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::SetPlayerAppValueNotification(
|
||||
const BluetoothAvrcpPlayerSettings& aSettings)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP application-setting-related functions
|
||||
}
|
||||
|
||||
/* This method returns element attributes, which are requested from
|
||||
* CT. Unlike BlueZ it calls only UpdateMetaData. Bluedroid does not cache
|
||||
* meta-data information, but instead uses |GetElementAttrNotifications|
|
||||
* and |GetElementAttrRsp| request them.
|
||||
*/
|
||||
void
|
||||
BluetoothAvrcpManager::GetElementAttrNotification(
|
||||
uint8_t aNumAttrs, const BluetoothAvrcpMediaAttribute* aAttrs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsAutoArrayPtr<BluetoothAvrcpElementAttribute> attrs(
|
||||
new BluetoothAvrcpElementAttribute[aNumAttrs]);
|
||||
|
||||
for (uint8_t i = 0; i < aNumAttrs; ++i) {
|
||||
attrs[i].mId = aAttrs[i];
|
||||
ConvertAttributeString(
|
||||
static_cast<BluetoothAvrcpMediaAttribute>(attrs[i].mId),
|
||||
attrs[i].mValue);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(sBtAvrcpInterface);
|
||||
sBtAvrcpInterface->GetElementAttrRsp(aNumAttrs, attrs, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::RegisterNotificationNotification(
|
||||
BluetoothAvrcpEvent aEvent, uint32_t aParam)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
|
||||
if (!avrcp) {
|
||||
return;
|
||||
}
|
||||
|
||||
avrcp->UpdateRegisterNotification(aEvent, aParam);
|
||||
}
|
||||
|
||||
/* This method is used to get CT features from the Feature Bit Mask. If
|
||||
* Advanced Control Player bit is set, the CT supports volume sync (absolute
|
||||
* volume feature). If Browsing bit is set, AVRCP 1.4 Browse feature will be
|
||||
* supported.
|
||||
*/
|
||||
void
|
||||
BluetoothAvrcpManager::RemoteFeatureNotification(
|
||||
const nsAString& aBdAddr, unsigned long aFeatures)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP 1.4 absolute volume/browse
|
||||
}
|
||||
|
||||
/* This method is used to get notifications about volume changes on the
|
||||
* remote car kit (if it supports AVRCP 1.4), not notification from phone.
|
||||
*/
|
||||
void
|
||||
BluetoothAvrcpManager::VolumeChangeNotification(uint8_t aVolume,
|
||||
uint8_t aCType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO: Support AVRCP 1.4 absolute volume/browse
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::PassthroughCmdNotification(int aId, int aKeyState)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Fast-forward and rewind key events won't be generated from bluedroid
|
||||
// stack after ANDROID_VERSION > 18, but via passthrough callback.
|
||||
nsAutoString name;
|
||||
NS_ENSURE_TRUE_VOID(aKeyState == AVRC_KEY_PRESS_STATE ||
|
||||
aKeyState == AVRC_KEY_RELEASE_STATE);
|
||||
switch (aId) {
|
||||
case AVRC_ID_FAST_FOR:
|
||||
if (aKeyState == AVRC_KEY_PRESS_STATE) {
|
||||
name.AssignLiteral("media-fast-forward-button-press");
|
||||
} else {
|
||||
name.AssignLiteral("media-fast-forward-button-release");
|
||||
}
|
||||
break;
|
||||
case AVRC_ID_REWIND:
|
||||
if (aKeyState == AVRC_KEY_PRESS_STATE) {
|
||||
name.AssignLiteral("media-rewind-button-press");
|
||||
} else {
|
||||
name.AssignLiteral("media-rewind-button-release");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BT_WARNING("Unable to handle the unknown PassThrough command %d", aId);
|
||||
return;
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_STRING(type, "media-button");
|
||||
BroadcastSystemMessage(type, BluetoothValue(name));
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(BluetoothAvrcpManager, nsIObserver)
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_bluetooth_bluedroid_BluetoothAvrcpManager_h
|
||||
#define mozilla_dom_bluetooth_bluedroid_BluetoothAvrcpManager_h
|
||||
|
||||
#include "BluetoothCommon.h"
|
||||
#include "BluetoothInterface.h"
|
||||
#include "BluetoothProfileController.h"
|
||||
#include "BluetoothProfileManagerBase.h"
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
class BluetoothAvrcpManager : public BluetoothProfileManagerBase
|
||||
, public BluetoothAvrcpNotificationHandler
|
||||
{
|
||||
public:
|
||||
BT_DECL_PROFILE_MGR_BASE
|
||||
virtual void GetName(nsACString& aName)
|
||||
{
|
||||
aName.AssignLiteral("AVRCP");
|
||||
}
|
||||
|
||||
enum SinkState {
|
||||
SINK_UNKNOWN,
|
||||
SINK_DISCONNECTED,
|
||||
SINK_CONNECTING,
|
||||
SINK_CONNECTED,
|
||||
SINK_PLAYING,
|
||||
};
|
||||
|
||||
static BluetoothAvrcpManager* Get();
|
||||
static void InitAvrcpInterface(BluetoothProfileResultHandler* aRes);
|
||||
static void DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes);
|
||||
|
||||
void SetConnected(bool aConnected);
|
||||
void UpdateMetaData(const nsAString& aTitle,
|
||||
const nsAString& aArtist,
|
||||
const nsAString& aAlbum,
|
||||
uint64_t aMediaNumber,
|
||||
uint64_t aTotalMediaCount,
|
||||
uint32_t aDuration);
|
||||
void UpdatePlayStatus(uint32_t aDuration,
|
||||
uint32_t aPosition,
|
||||
ControlPlayStatus aPlayStatus);
|
||||
void UpdateRegisterNotification(BluetoothAvrcpEvent aEvent, uint32_t aParam);
|
||||
void GetAlbum(nsAString& aAlbum);
|
||||
uint32_t GetDuration();
|
||||
ControlPlayStatus GetPlayStatus();
|
||||
uint32_t GetPosition();
|
||||
uint64_t GetMediaNumber();
|
||||
uint64_t GetTotalMediaNumber();
|
||||
void GetTitle(nsAString& aTitle);
|
||||
void GetArtist(nsAString& aArtist);
|
||||
void HandleBackendError();
|
||||
|
||||
protected:
|
||||
virtual ~BluetoothAvrcpManager();
|
||||
|
||||
private:
|
||||
class CleanupAvrcpResultHandler;
|
||||
class CleanupAvrcpResultHandlerRunnable;
|
||||
class ConnectResultHandler;
|
||||
class DisconnectResultHandler;
|
||||
class InitAvrcpResultHandler;
|
||||
class OnErrorProfileResultHandlerRunnable;
|
||||
|
||||
BluetoothAvrcpManager();
|
||||
|
||||
void HandleShutdown();
|
||||
void NotifyConnectionStatusChanged();
|
||||
|
||||
void GetPlayStatusNotification() override;
|
||||
|
||||
void ListPlayerAppAttrNotification() override;
|
||||
|
||||
void ListPlayerAppValuesNotification(
|
||||
BluetoothAvrcpPlayerAttribute aAttrId) override;
|
||||
|
||||
void GetPlayerAppValueNotification(
|
||||
uint8_t aNumAttrs,
|
||||
const BluetoothAvrcpPlayerAttribute* aAttrs) override;
|
||||
|
||||
void GetPlayerAppAttrsTextNotification(
|
||||
uint8_t aNumAttrs,
|
||||
const BluetoothAvrcpPlayerAttribute* aAttrs) override;
|
||||
|
||||
void GetPlayerAppValuesTextNotification(
|
||||
uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues) override;
|
||||
|
||||
void SetPlayerAppValueNotification(
|
||||
const BluetoothAvrcpPlayerSettings& aSettings) override;
|
||||
|
||||
void GetElementAttrNotification(
|
||||
uint8_t aNumAttrs,
|
||||
const BluetoothAvrcpMediaAttribute* aAttrs) override;
|
||||
|
||||
void RegisterNotificationNotification(
|
||||
BluetoothAvrcpEvent aEvent, uint32_t aParam) override;
|
||||
|
||||
void RemoteFeatureNotification(
|
||||
const nsAString& aBdAddr, unsigned long aFeatures) override;
|
||||
|
||||
void VolumeChangeNotification(uint8_t aVolume, uint8_t aCType) override;
|
||||
|
||||
void PassthroughCmdNotification(int aId, int aKeyState) override;
|
||||
|
||||
nsString mDeviceAddress;
|
||||
nsRefPtr<BluetoothProfileController> mController;
|
||||
|
||||
bool mAvrcpConnected;
|
||||
nsString mAlbum;
|
||||
nsString mArtist;
|
||||
nsString mTitle;
|
||||
uint32_t mDuration;
|
||||
uint64_t mMediaNumber;
|
||||
uint64_t mTotalMediaCount;
|
||||
uint32_t mPosition;
|
||||
/*
|
||||
* mPlaybackInterval specifies the time interval (in seconds) at which
|
||||
* the change in playback position will be notified. If the song is being
|
||||
* forwarded / rewound, a notification will be received whenever the playback
|
||||
* position will change by this value.
|
||||
*/
|
||||
uint32_t mPlaybackInterval;
|
||||
ControlPlayStatus mPlayStatus;
|
||||
/*
|
||||
* Notification types: 1. INTERIM 2. CHANGED
|
||||
* 1. The initial response to this Notify command shall be an INTERIM
|
||||
* response with current status.
|
||||
* 2. The following response shall be a CHANGED response with the updated
|
||||
* status.
|
||||
* mPlayStatusChangedNotifType, mTrackChangedNotifType,
|
||||
* mPlayPosChangedNotifType represents current RegisterNotification
|
||||
* notification type.
|
||||
*/
|
||||
BluetoothAvrcpNotification mPlayStatusChangedNotifyType;
|
||||
BluetoothAvrcpNotification mTrackChangedNotifyType;
|
||||
BluetoothAvrcpNotification mPlayPosChangedNotifyType;
|
||||
BluetoothAvrcpNotification mAppSettingsChangedNotifyType;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_bluetooth_bluedroid_BluetoothAvrcpManager_h
|
|
@ -19,6 +19,7 @@
|
|||
#include "BluetoothServiceBluedroid.h"
|
||||
|
||||
#include "BluetoothA2dpManager.h"
|
||||
#include "BluetoothAvrcpManager.h"
|
||||
#include "BluetoothGattManager.h"
|
||||
#include "BluetoothHfpManager.h"
|
||||
#include "BluetoothHidManager.h"
|
||||
|
@ -154,6 +155,7 @@ public:
|
|||
static void (* const sInitManager[])(BluetoothProfileResultHandler*) = {
|
||||
BluetoothHfpManager::InitHfpInterface,
|
||||
BluetoothA2dpManager::InitA2dpInterface,
|
||||
BluetoothAvrcpManager::InitAvrcpInterface,
|
||||
BluetoothGattManager::InitGattInterface
|
||||
};
|
||||
|
||||
|
@ -295,6 +297,7 @@ BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
|
|||
|
||||
static BluetoothProfileManagerBase* sProfiles[] = {
|
||||
BluetoothHfpManager::Get(),
|
||||
BluetoothAvrcpManager::Get(),
|
||||
BluetoothA2dpManager::Get(),
|
||||
BluetoothOppManager::Get(),
|
||||
BluetoothPbapManager::Get(),
|
||||
|
@ -1282,10 +1285,10 @@ BluetoothServiceBluedroid::SendMetaData(const nsAString& aTitle,
|
|||
int64_t aDuration,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
if (a2dp) {
|
||||
a2dp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber,
|
||||
aTotalMediaCount, aDuration);
|
||||
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
|
||||
if (avrcp) {
|
||||
avrcp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber,
|
||||
aTotalMediaCount, aDuration);
|
||||
}
|
||||
DispatchReplySuccess(aRunnable);
|
||||
}
|
||||
|
@ -1296,11 +1299,11 @@ BluetoothServiceBluedroid::SendPlayStatus(
|
|||
const nsAString& aPlayStatus,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
if (a2dp) {
|
||||
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
|
||||
if (avrcp) {
|
||||
ControlPlayStatus playStatus =
|
||||
PlayStatusStringToControlPlayStatus(aPlayStatus);
|
||||
a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus);
|
||||
avrcp->UpdatePlayStatus(aDuration, aPosition, playStatus);
|
||||
}
|
||||
DispatchReplySuccess(aRunnable);
|
||||
}
|
||||
|
|
|
@ -52,8 +52,9 @@ BluetoothA2dpManager::BluetoothA2dpManager()
|
|||
void
|
||||
BluetoothA2dpManager::Reset()
|
||||
{
|
||||
ResetA2dp();
|
||||
ResetAvrcp();
|
||||
mA2dpConnected = false;
|
||||
mSinkState = SinkState::SINK_DISCONNECTED;
|
||||
mController = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -80,25 +81,6 @@ BluetoothA2dpManager::~BluetoothA2dpManager()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::ResetA2dp()
|
||||
{
|
||||
mA2dpConnected = false;
|
||||
mSinkState = SinkState::SINK_DISCONNECTED;
|
||||
mController = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::ResetAvrcp()
|
||||
{
|
||||
mAvrcpConnected = false;
|
||||
mDuration = 0;
|
||||
mMediaNumber = 0;
|
||||
mTotalMediaCount = 0;
|
||||
mPosition = 0;
|
||||
mPlayStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
static BluetoothA2dpManager::SinkState
|
||||
StatusStringToSinkState(const nsAString& aStatus)
|
||||
{
|
||||
|
@ -399,82 +381,4 @@ BluetoothA2dpManager::IsConnected()
|
|||
return mA2dpConnected;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::SetAvrcpConnected(bool aConnected)
|
||||
{
|
||||
mAvrcpConnected = aConnected;
|
||||
if (!aConnected) {
|
||||
ResetAvrcp();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothA2dpManager::IsAvrcpConnected()
|
||||
{
|
||||
return mAvrcpConnected;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::UpdateMetaData(const nsAString& aTitle,
|
||||
const nsAString& aArtist,
|
||||
const nsAString& aAlbum,
|
||||
uint64_t aMediaNumber,
|
||||
uint64_t aTotalMediaCount,
|
||||
uint32_t aDuration)
|
||||
{
|
||||
mTitle.Assign(aTitle);
|
||||
mArtist.Assign(aArtist);
|
||||
mAlbum.Assign(aAlbum);
|
||||
mMediaNumber = aMediaNumber;
|
||||
mTotalMediaCount = aTotalMediaCount;
|
||||
mDuration = aDuration;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::UpdatePlayStatus(uint32_t aDuration,
|
||||
uint32_t aPosition,
|
||||
ControlPlayStatus aPlayStatus)
|
||||
{
|
||||
mDuration = aDuration;
|
||||
mPosition = aPosition;
|
||||
mPlayStatus = aPlayStatus;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::GetAlbum(nsAString& aAlbum)
|
||||
{
|
||||
aAlbum.Assign(mAlbum);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BluetoothA2dpManager::GetDuration()
|
||||
{
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
ControlPlayStatus
|
||||
BluetoothA2dpManager::GetPlayStatus()
|
||||
{
|
||||
return mPlayStatus;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BluetoothA2dpManager::GetPosition()
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
BluetoothA2dpManager::GetMediaNumber()
|
||||
{
|
||||
return mMediaNumber;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothA2dpManager::GetTitle(nsAString& aTitle)
|
||||
{
|
||||
aTitle.Assign(mTitle);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(BluetoothA2dpManager, nsIObserver)
|
||||
|
||||
|
|
|
@ -35,25 +35,6 @@ public:
|
|||
// A2DP-specific functions
|
||||
void HandleSinkPropertyChanged(const BluetoothSignal& aSignal);
|
||||
|
||||
// AVRCP-specific functions
|
||||
void SetAvrcpConnected(bool aConnected);
|
||||
bool IsAvrcpConnected();
|
||||
void UpdateMetaData(const nsAString& aTitle,
|
||||
const nsAString& aArtist,
|
||||
const nsAString& aAlbum,
|
||||
uint64_t aMediaNumber,
|
||||
uint64_t aTotalMediaCount,
|
||||
uint32_t aDuration);
|
||||
void UpdatePlayStatus(uint32_t aDuration,
|
||||
uint32_t aPosition,
|
||||
ControlPlayStatus aPlayStatus);
|
||||
void GetAlbum(nsAString& aAlbum);
|
||||
uint32_t GetDuration();
|
||||
ControlPlayStatus GetPlayStatus();
|
||||
uint32_t GetPosition();
|
||||
uint64_t GetMediaNumber();
|
||||
void GetTitle(nsAString& aTitle);
|
||||
|
||||
protected:
|
||||
virtual ~BluetoothA2dpManager();
|
||||
|
||||
|
@ -61,7 +42,6 @@ private:
|
|||
BluetoothA2dpManager();
|
||||
bool Init();
|
||||
void ResetA2dp();
|
||||
void ResetAvrcp();
|
||||
|
||||
void HandleShutdown();
|
||||
void NotifyConnectionStatusChanged();
|
||||
|
@ -73,16 +53,6 @@ private:
|
|||
bool mA2dpConnected;
|
||||
SinkState mSinkState;
|
||||
|
||||
// AVRCP data member
|
||||
bool mAvrcpConnected;
|
||||
nsString mAlbum;
|
||||
nsString mArtist;
|
||||
nsString mTitle;
|
||||
uint32_t mDuration;
|
||||
uint64_t mMediaNumber;
|
||||
uint64_t mTotalMediaCount;
|
||||
uint32_t mPosition;
|
||||
ControlPlayStatus mPlayStatus;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
/* -*- 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 "base/basictypes.h"
|
||||
|
||||
#include "BluetoothAvrcpManager.h"
|
||||
|
||||
#include "BluetoothCommon.h"
|
||||
#include "BluetoothService.h"
|
||||
#include "BluetoothSocket.h"
|
||||
#include "BluetoothUtils.h"
|
||||
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "MainThreadUtils.h"
|
||||
|
||||
|
||||
using namespace mozilla;
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
namespace {
|
||||
StaticRefPtr<BluetoothAvrcpManager> sBluetoothAvrcpManager;
|
||||
bool sInShutdown = false;
|
||||
} // namespace
|
||||
|
||||
NS_IMETHODIMP
|
||||
BluetoothAvrcpManager::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(sBluetoothAvrcpManager);
|
||||
|
||||
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
||||
HandleShutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "BluetoothAvrcpManager got unexpected topic!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
BluetoothAvrcpManager::BluetoothAvrcpManager()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::Reset()
|
||||
{
|
||||
mAvrcpConnected = false;
|
||||
mDuration = 0;
|
||||
mMediaNumber = 0;
|
||||
mTotalMediaCount = 0;
|
||||
mPosition = 0;
|
||||
mPlayStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothAvrcpManager::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE(obs, false);
|
||||
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
|
||||
BT_WARNING("Failed to add shutdown observer!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BluetoothAvrcpManager::~BluetoothAvrcpManager()
|
||||
{
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
BluetoothAvrcpManager*
|
||||
BluetoothAvrcpManager::Get()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// If sBluetoothA2dpManager already exists, exit early
|
||||
if (sBluetoothAvrcpManager) {
|
||||
return sBluetoothAvrcpManager;
|
||||
}
|
||||
|
||||
// If we're in shutdown, don't create a new instance
|
||||
NS_ENSURE_FALSE(sInShutdown, nullptr);
|
||||
|
||||
// Create a new instance, register, and return
|
||||
BluetoothAvrcpManager* manager = new BluetoothAvrcpManager();
|
||||
NS_ENSURE_TRUE(manager->Init(), nullptr);
|
||||
|
||||
sBluetoothAvrcpManager = manager;
|
||||
return sBluetoothAvrcpManager;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::HandleShutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
sInShutdown = true;
|
||||
Disconnect(nullptr);
|
||||
sBluetoothAvrcpManager = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::Connect(const nsAString& aDeviceAddress,
|
||||
BluetoothProfileController* aController)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
|
||||
MOZ_ASSERT(aController && !mController);
|
||||
|
||||
mDeviceAddress = aDeviceAddress;
|
||||
OnConnect(EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::Disconnect(BluetoothProfileController* aController)
|
||||
{
|
||||
mDeviceAddress.Truncate();
|
||||
OnDisconnect(EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::OnConnect(const nsAString& aErrorStr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
/**
|
||||
* On the one hand, notify the controller that we've done for outbound
|
||||
* connections. On the other hand, we do nothing for inbound connections.
|
||||
*/
|
||||
NS_ENSURE_TRUE_VOID(mController);
|
||||
|
||||
nsRefPtr<BluetoothProfileController> controller = mController.forget();
|
||||
controller->NotifyCompletion(aErrorStr);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::OnDisconnect(const nsAString& aErrorStr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
/**
|
||||
* On the one hand, notify the controller that we've done for outbound
|
||||
* connections. On the other hand, we do nothing for inbound connections.
|
||||
*/
|
||||
NS_ENSURE_TRUE_VOID(mController);
|
||||
|
||||
nsRefPtr<BluetoothProfileController> controller = mController.forget();
|
||||
controller->NotifyCompletion(aErrorStr);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
|
||||
const nsAString& aServiceUuid,
|
||||
int aChannel)
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetAddress(nsAString& aDeviceAddress)
|
||||
{
|
||||
aDeviceAddress = mDeviceAddress;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothAvrcpManager::IsConnected()
|
||||
{
|
||||
return mAvrcpConnected;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::SetConnected(bool aConnected)
|
||||
{
|
||||
mAvrcpConnected = aConnected;
|
||||
if (!aConnected) {
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::UpdateMetaData(const nsAString& aTitle,
|
||||
const nsAString& aArtist,
|
||||
const nsAString& aAlbum,
|
||||
uint64_t aMediaNumber,
|
||||
uint64_t aTotalMediaCount,
|
||||
uint32_t aDuration)
|
||||
{
|
||||
mTitle.Assign(aTitle);
|
||||
mArtist.Assign(aArtist);
|
||||
mAlbum.Assign(aAlbum);
|
||||
mMediaNumber = aMediaNumber;
|
||||
mTotalMediaCount = aTotalMediaCount;
|
||||
mDuration = aDuration;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::UpdatePlayStatus(uint32_t aDuration,
|
||||
uint32_t aPosition,
|
||||
ControlPlayStatus aPlayStatus)
|
||||
{
|
||||
mDuration = aDuration;
|
||||
mPosition = aPosition;
|
||||
mPlayStatus = aPlayStatus;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetAlbum(nsAString& aAlbum)
|
||||
{
|
||||
aAlbum.Assign(mAlbum);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BluetoothAvrcpManager::GetDuration()
|
||||
{
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
ControlPlayStatus
|
||||
BluetoothAvrcpManager::GetPlayStatus()
|
||||
{
|
||||
return mPlayStatus;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BluetoothAvrcpManager::GetPosition()
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
BluetoothAvrcpManager::GetMediaNumber()
|
||||
{
|
||||
return mMediaNumber;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAvrcpManager::GetTitle(nsAString& aTitle)
|
||||
{
|
||||
aTitle.Assign(mTitle);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(BluetoothAvrcpManager, nsIObserver)
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_bluetooth_bluez_BluetoothAvrcpManager_h
|
||||
#define mozilla_dom_bluetooth_bluez_BluetoothAvrcpManager_h
|
||||
|
||||
#include "BluetoothCommon.h"
|
||||
#include "BluetoothProfileController.h"
|
||||
#include "BluetoothProfileManagerBase.h"
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothAvrcpManager : public BluetoothProfileManagerBase
|
||||
{
|
||||
public:
|
||||
BT_DECL_PROFILE_MGR_BASE
|
||||
virtual void GetName(nsACString& aName)
|
||||
{
|
||||
aName.AssignLiteral("AVRCP");
|
||||
}
|
||||
|
||||
static BluetoothAvrcpManager* Get();
|
||||
|
||||
// AVRCP-specific functions
|
||||
void SetConnected(bool aConnected);
|
||||
void UpdateMetaData(const nsAString& aTitle,
|
||||
const nsAString& aArtist,
|
||||
const nsAString& aAlbum,
|
||||
uint64_t aMediaNumber,
|
||||
uint64_t aTotalMediaCount,
|
||||
uint32_t aDuration);
|
||||
void UpdatePlayStatus(uint32_t aDuration,
|
||||
uint32_t aPosition,
|
||||
ControlPlayStatus aPlayStatus);
|
||||
void GetAlbum(nsAString& aAlbum);
|
||||
uint32_t GetDuration();
|
||||
ControlPlayStatus GetPlayStatus();
|
||||
uint32_t GetPosition();
|
||||
uint64_t GetMediaNumber();
|
||||
void GetTitle(nsAString& aTitle);
|
||||
|
||||
protected:
|
||||
virtual ~BluetoothAvrcpManager();
|
||||
|
||||
private:
|
||||
BluetoothAvrcpManager();
|
||||
bool Init();
|
||||
|
||||
void HandleShutdown();
|
||||
void NotifyConnectionStatusChanged();
|
||||
|
||||
nsString mDeviceAddress;
|
||||
nsRefPtr<BluetoothProfileController> mController;
|
||||
|
||||
// AVRCP data member
|
||||
bool mAvrcpConnected;
|
||||
nsString mAlbum;
|
||||
nsString mArtist;
|
||||
nsString mTitle;
|
||||
uint32_t mDuration;
|
||||
uint64_t mMediaNumber;
|
||||
uint64_t mTotalMediaCount;
|
||||
uint32_t mPosition;
|
||||
ControlPlayStatus mPlayStatus;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_bluetooth_bluez_BluetoothAvrcpManager_h
|
|
@ -19,6 +19,7 @@
|
|||
#include "base/basictypes.h"
|
||||
#include "BluetoothDBusService.h"
|
||||
#include "BluetoothA2dpManager.h"
|
||||
#include "BluetoothAvrcpManager.h"
|
||||
#include "BluetoothHfpManager.h"
|
||||
#include "BluetoothHidManager.h"
|
||||
#include "BluetoothOppManager.h"
|
||||
|
@ -538,9 +539,9 @@ public:
|
|||
MOZ_ASSERT(arr[0].value().type() == BluetoothValue::Tbool);
|
||||
bool connected = arr[0].value().get_bool();
|
||||
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
NS_ENSURE_TRUE(a2dp, NS_ERROR_FAILURE);
|
||||
a2dp->SetAvrcpConnected(connected);
|
||||
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
|
||||
NS_ENSURE_TRUE(avrcp, NS_ERROR_FAILURE);
|
||||
avrcp->SetConnected(connected);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3957,32 +3958,28 @@ BluetoothDBusService::SendMetaData(const nsAString& aTitle,
|
|||
return;
|
||||
}
|
||||
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(a2dp);
|
||||
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(avrcp);
|
||||
|
||||
if (!a2dp->IsConnected()) {
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(),
|
||||
NS_LITERAL_STRING(ERR_A2DP_IS_DISCONNECTED));
|
||||
return;
|
||||
} else if (!a2dp->IsAvrcpConnected()) {
|
||||
if (!avrcp->IsConnected()) {
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(),
|
||||
NS_LITERAL_STRING(ERR_AVRCP_IS_DISCONNECTED));
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString prevTitle, prevAlbum;
|
||||
a2dp->GetTitle(prevTitle);
|
||||
a2dp->GetAlbum(prevAlbum);
|
||||
avrcp->GetTitle(prevTitle);
|
||||
avrcp->GetAlbum(prevAlbum);
|
||||
|
||||
uint64_t mediaNumber = static_cast<uint64_t>(aMediaNumber);
|
||||
if (mediaNumber != a2dp->GetMediaNumber() ||
|
||||
if (mediaNumber != avrcp->GetMediaNumber() ||
|
||||
!aTitle.Equals(prevTitle) ||
|
||||
!aAlbum.Equals(prevAlbum)) {
|
||||
UpdateNotification(ControlEventId::EVENT_TRACK_CHANGED, aMediaNumber);
|
||||
}
|
||||
|
||||
nsAutoString deviceAddress;
|
||||
a2dp->GetAddress(deviceAddress);
|
||||
avrcp->GetAddress(deviceAddress);
|
||||
|
||||
Task* task = new SendMetadataTask(
|
||||
deviceAddress,
|
||||
|
@ -3995,8 +3992,8 @@ BluetoothDBusService::SendMetaData(const nsAString& aTitle,
|
|||
aRunnable);
|
||||
DispatchToDBusThread(task);
|
||||
|
||||
a2dp->UpdateMetaData(aTitle, aArtist, aAlbum,
|
||||
aMediaNumber, aTotalMediaCount, aDuration);
|
||||
avrcp->UpdateMetaData(aTitle, aArtist, aAlbum,
|
||||
aMediaNumber, aTotalMediaCount, aDuration);
|
||||
}
|
||||
|
||||
static ControlPlayStatus
|
||||
|
@ -4101,28 +4098,24 @@ BluetoothDBusService::SendPlayStatus(int64_t aDuration,
|
|||
return;
|
||||
}
|
||||
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(a2dp);
|
||||
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(avrcp);
|
||||
|
||||
if (!a2dp->IsConnected()) {
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(),
|
||||
NS_LITERAL_STRING(ERR_A2DP_IS_DISCONNECTED));
|
||||
return;
|
||||
} else if (!a2dp->IsAvrcpConnected()) {
|
||||
if (!avrcp->IsConnected()) {
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(),
|
||||
NS_LITERAL_STRING(ERR_AVRCP_IS_DISCONNECTED));
|
||||
return;
|
||||
}
|
||||
|
||||
if (playStatus != a2dp->GetPlayStatus()) {
|
||||
if (playStatus != avrcp->GetPlayStatus()) {
|
||||
UpdateNotification(ControlEventId::EVENT_PLAYBACK_STATUS_CHANGED,
|
||||
playStatus);
|
||||
} else if (aPosition != a2dp->GetPosition()) {
|
||||
} else if (aPosition != avrcp->GetPosition()) {
|
||||
UpdateNotification(ControlEventId::EVENT_PLAYBACK_POS_CHANGED, aPosition);
|
||||
}
|
||||
|
||||
nsAutoString deviceAddress;
|
||||
a2dp->GetAddress(deviceAddress);
|
||||
avrcp->GetAddress(deviceAddress);
|
||||
|
||||
Task* task = new SendPlayStatusTask(deviceAddress,
|
||||
aDuration,
|
||||
|
@ -4131,7 +4124,7 @@ BluetoothDBusService::SendPlayStatus(int64_t aDuration,
|
|||
aRunnable);
|
||||
DispatchToDBusThread(task);
|
||||
|
||||
a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus);
|
||||
avrcp->UpdatePlayStatus(aDuration, aPosition, playStatus);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -4200,14 +4193,13 @@ BluetoothDBusService::UpdatePlayStatus(uint32_t aDuration,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE_VOID(this->IsReady());
|
||||
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(a2dp);
|
||||
MOZ_ASSERT(a2dp->IsConnected());
|
||||
MOZ_ASSERT(a2dp->IsAvrcpConnected());
|
||||
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(avrcp);
|
||||
MOZ_ASSERT(avrcp->IsConnected());
|
||||
MOZ_ASSERT(!sAdapterPath.IsEmpty());
|
||||
|
||||
nsAutoString deviceAddress;
|
||||
a2dp->GetAddress(deviceAddress);
|
||||
avrcp->GetAddress(deviceAddress);
|
||||
|
||||
Task* task = new UpdatePlayStatusTask(deviceAddress,
|
||||
aDuration,
|
||||
|
@ -4264,14 +4256,13 @@ BluetoothDBusService::UpdateNotification(ControlEventId aEventId,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE_VOID(this->IsReady());
|
||||
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(a2dp);
|
||||
MOZ_ASSERT(a2dp->IsConnected());
|
||||
MOZ_ASSERT(a2dp->IsAvrcpConnected());
|
||||
BluetoothAvrcpManager* avrcp = BluetoothAvrcpManager::Get();
|
||||
NS_ENSURE_TRUE_VOID(avrcp);
|
||||
MOZ_ASSERT(avrcp->IsConnected());
|
||||
MOZ_ASSERT(!sAdapterPath.IsEmpty());
|
||||
|
||||
nsAutoString deviceAddress;
|
||||
a2dp->GetAddress(deviceAddress);
|
||||
avrcp->GetAddress(deviceAddress);
|
||||
|
||||
Task* task = new UpdateNotificationTask(deviceAddress, aEventId, aData);
|
||||
DispatchToDBusThread(task);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "BluetoothProfileController.h"
|
||||
|
||||
#include "BluetoothA2dpManager.h"
|
||||
#include "BluetoothAvrcpManager.h"
|
||||
#include "BluetoothHfpManager.h"
|
||||
#include "BluetoothHidManager.h"
|
||||
#include "BluetoothReplyRunnable.h"
|
||||
|
@ -111,6 +112,9 @@ BluetoothProfileController::AddProfileWithServiceClass(
|
|||
case BluetoothServiceClass::A2DP:
|
||||
profile = BluetoothA2dpManager::Get();
|
||||
break;
|
||||
case BluetoothServiceClass::AVRCP:
|
||||
profile = BluetoothAvrcpManager::Get();
|
||||
break;
|
||||
case BluetoothServiceClass::HID:
|
||||
profile = BluetoothHidManager::Get();
|
||||
break;
|
||||
|
@ -158,6 +162,7 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
|
|||
// For a disconnect request, all connected profiles are put into array.
|
||||
if (!mConnect) {
|
||||
AddProfile(BluetoothHidManager::Get(), true);
|
||||
AddProfile(BluetoothAvrcpManager::Get(), true);
|
||||
AddProfile(BluetoothA2dpManager::Get(), true);
|
||||
AddProfile(BluetoothHfpManager::Get(), true);
|
||||
return;
|
||||
|
@ -180,6 +185,7 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
|
|||
if (isInvalid) {
|
||||
AddProfile(BluetoothHfpManager::Get());
|
||||
AddProfile(BluetoothA2dpManager::Get());
|
||||
AddProfile(BluetoothAvrcpManager::Get()); // register after A2DP
|
||||
AddProfile(BluetoothHidManager::Get());
|
||||
return;
|
||||
}
|
||||
|
@ -196,6 +202,7 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
|
|||
// a remote control.
|
||||
if (hasRendering || (isPeripheral && isRemoteControl)) {
|
||||
AddProfile(BluetoothA2dpManager::Get());
|
||||
AddProfile(BluetoothAvrcpManager::Get()); // register after A2DP
|
||||
}
|
||||
|
||||
// A device which supports HID should claim that it's a peripheral and it's
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "BluetoothUuid.h"
|
||||
|
||||
#include "BluetoothA2dpManager.h"
|
||||
#include "BluetoothAvrcpManager.h"
|
||||
#include "BluetoothHfpManager.h"
|
||||
#include "BluetoothHidManager.h"
|
||||
#include "BluetoothOppManager.h"
|
||||
|
@ -52,6 +53,9 @@ BluetoothUuidHelper::GetBluetoothServiceClass(uint16_t aServiceUuid)
|
|||
switch (aServiceUuid) {
|
||||
case BluetoothServiceClass::A2DP:
|
||||
case BluetoothServiceClass::A2DP_SINK:
|
||||
case BluetoothServiceClass::AVRCP:
|
||||
case BluetoothServiceClass::AVRCP_TARGET:
|
||||
case BluetoothServiceClass::AVRCP_CONTROLLER:
|
||||
case BluetoothServiceClass::HANDSFREE:
|
||||
case BluetoothServiceClass::HANDSFREE_AG:
|
||||
case BluetoothServiceClass::HEADSET:
|
||||
|
@ -79,6 +83,9 @@ BluetoothUuidHelper::GetBluetoothProfileManager(uint16_t aServiceUuid)
|
|||
case BluetoothServiceClass::A2DP:
|
||||
profile = BluetoothA2dpManager::Get();
|
||||
break;
|
||||
case BluetoothServiceClass::AVRCP:
|
||||
profile = BluetoothAvrcpManager::Get();
|
||||
break;
|
||||
case BluetoothServiceClass::OBJECT_PUSH:
|
||||
profile = BluetoothOppManager::Get();
|
||||
break;
|
||||
|
|
|
@ -24,15 +24,18 @@ class BluetoothProfileManagerBase;
|
|||
*/
|
||||
enum BluetoothServiceClass
|
||||
{
|
||||
A2DP = 0x110D,
|
||||
A2DP_SINK = 0x110B,
|
||||
HANDSFREE = 0x111E,
|
||||
HANDSFREE_AG = 0x111F,
|
||||
HEADSET = 0x1108,
|
||||
HEADSET_AG = 0x1112,
|
||||
HID = 0x1124,
|
||||
OBJECT_PUSH = 0x1105,
|
||||
UNKNOWN = 0x0000
|
||||
A2DP = 0x110D,
|
||||
A2DP_SINK = 0x110B,
|
||||
AVRCP = 0x110E,
|
||||
AVRCP_TARGET = 0x110C,
|
||||
AVRCP_CONTROLLER = 0x110F,
|
||||
HANDSFREE = 0x111E,
|
||||
HANDSFREE_AG = 0x111F,
|
||||
HEADSET = 0x1108,
|
||||
HEADSET_AG = 0x1112,
|
||||
HID = 0x1124,
|
||||
OBJECT_PUSH = 0x1105,
|
||||
UNKNOWN = 0x0000
|
||||
};
|
||||
|
||||
class BluetoothUuidHelper
|
||||
|
|
|
@ -57,6 +57,7 @@ if CONFIG['MOZ_B2G_BT']:
|
|||
CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
|
||||
SOURCES += [
|
||||
'bluez/BluetoothA2dpManager.cpp',
|
||||
'bluez/BluetoothAvrcpManager.cpp',
|
||||
'bluez/BluetoothDBusService.cpp',
|
||||
'bluez/BluetoothHfpManager.cpp',
|
||||
'bluez/BluetoothOppManager.cpp',
|
||||
|
@ -70,6 +71,7 @@ if CONFIG['MOZ_B2G_BT']:
|
|||
elif CONFIG['MOZ_B2G_BT_DAEMON']:
|
||||
SOURCES += [
|
||||
'bluedroid/BluetoothA2dpManager.cpp',
|
||||
'bluedroid/BluetoothAvrcpManager.cpp',
|
||||
'bluedroid/BluetoothDaemonA2dpInterface.cpp',
|
||||
'bluedroid/BluetoothDaemonAvrcpInterface.cpp',
|
||||
'bluedroid/BluetoothDaemonGattInterface.cpp',
|
||||
|
|
|
@ -41,9 +41,15 @@ class DeviceStorageFileSystem;
|
|||
} // namespace dom
|
||||
namespace ipc {
|
||||
class FileDescriptor;
|
||||
class PrincipalInfo;
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
class DeviceStorageRequest;
|
||||
class DeviceStorageCursorRequest;
|
||||
class DeviceStorageRequestManager;
|
||||
class nsDOMDeviceStorageCursor;
|
||||
|
||||
class DeviceStorageFile final
|
||||
: public nsISupports {
|
||||
public:
|
||||
|
@ -197,10 +203,6 @@ public:
|
|||
AppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
|
||||
const int32_t aRequestType, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
Get(const nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
|
@ -290,16 +292,32 @@ public:
|
|||
void OnVolumeStateChanged(nsIVolume* aVolume);
|
||||
#endif
|
||||
|
||||
uint32_t CreateDOMRequest(DOMRequest** aRequest, ErrorResult& aRv);
|
||||
uint32_t CreateDOMCursor(DeviceStorageCursorRequest* aRequest,
|
||||
nsDOMDeviceStorageCursor** aCursor,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<DOMRequest> CreateAndRejectDOMRequest(const char *aReason,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsresult CheckPermission(DeviceStorageRequest* aRequest);
|
||||
void StorePermission(DeviceStorageRequest* aRequest, bool aAllow);
|
||||
|
||||
bool IsOwningThread();
|
||||
nsresult DispatchToOwningThread(nsIRunnable* aRunnable);
|
||||
|
||||
private:
|
||||
~nsDOMDeviceStorage();
|
||||
|
||||
static nsresult CheckPrincipal(nsPIDOMWindow* aWindow, bool aIsAppsStorage,
|
||||
nsIPrincipal** aPrincipal);
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
|
||||
bool aCreate, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
GetInternal(const nsAString& aPath, bool aEditable, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
GetInternal(nsPIDOMWindow* aWin, const nsAString& aPath, DOMRequest* aRequest,
|
||||
bool aEditable);
|
||||
|
||||
void
|
||||
DeleteInternal(nsPIDOMWindow* aWin, const nsAString& aPath,
|
||||
DOMRequest* aRequest);
|
||||
|
@ -327,10 +345,6 @@ private:
|
|||
const nsAString& aStorageName,
|
||||
const nsAString& aType);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
bool mIsWatchingFile;
|
||||
bool mAllowedToWatchFile;
|
||||
bool mIsDefaultLocation;
|
||||
|
||||
nsresult Notify(const char* aReason, class DeviceStorageFile* aFile);
|
||||
|
@ -347,7 +361,11 @@ private:
|
|||
void DispatchStorageStatusChangeEvent(nsAString& aStorageStatus);
|
||||
#endif
|
||||
|
||||
uint64_t mInnerWindowID;
|
||||
nsRefPtr<DeviceStorageFileSystem> mFileSystem;
|
||||
nsRefPtr<DeviceStorageRequestManager> mManager;
|
||||
nsAutoPtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
|
||||
nsCOMPtr<nsIThread> mOwningThread;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMDeviceStorage, NS_DOM_DEVICE_STORAGE_CID)
|
||||
|
|
|
@ -16,33 +16,14 @@ namespace dom {
|
|||
namespace devicestorage {
|
||||
|
||||
DeviceStorageRequestChild::DeviceStorageRequestChild()
|
||||
: mCallback(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
|
||||
}
|
||||
|
||||
DeviceStorageRequestChild::DeviceStorageRequestChild(DOMRequest* aRequest,
|
||||
DeviceStorageFile* aDSFile)
|
||||
DeviceStorageRequestChild::DeviceStorageRequestChild(DeviceStorageRequest* aRequest)
|
||||
: mRequest(aRequest)
|
||||
, mDSFile(aDSFile)
|
||||
, mCallback(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aRequest);
|
||||
MOZ_ASSERT(aDSFile);
|
||||
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
|
||||
}
|
||||
|
||||
DeviceStorageRequestChild::DeviceStorageRequestChild(DOMRequest* aRequest,
|
||||
DeviceStorageFile* aDSFile,
|
||||
DeviceStorageFileDescriptor* aDSFileDescriptor)
|
||||
: mRequest(aRequest)
|
||||
, mDSFile(aDSFile)
|
||||
, mDSFileDescriptor(aDSFileDescriptor)
|
||||
, mCallback(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aRequest);
|
||||
MOZ_ASSERT(aDSFile);
|
||||
MOZ_ASSERT(aDSFileDescriptor);
|
||||
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
|
||||
}
|
||||
|
||||
|
@ -54,160 +35,126 @@ bool
|
|||
DeviceStorageRequestChild::
|
||||
Recv__delete__(const DeviceStorageResponseValue& aValue)
|
||||
{
|
||||
if (mCallback) {
|
||||
mCallback->RequestComplete();
|
||||
mCallback = nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner();
|
||||
if (!window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (aValue.type()) {
|
||||
|
||||
case DeviceStorageResponseValue::TErrorResponse:
|
||||
{
|
||||
DS_LOG_INFO("error %u", mRequest->GetId());
|
||||
ErrorResponse r = aValue;
|
||||
mRequest->FireError(r.error());
|
||||
mRequest->Reject(r.error());
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TSuccessResponse:
|
||||
{
|
||||
DS_LOG_INFO("success %u", mRequest->GetId());
|
||||
nsString fullPath;
|
||||
mDSFile->GetFullPath(fullPath);
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
StringToJsval(window, fullPath, &result);
|
||||
mRequest->FireSuccess(result);
|
||||
mRequest->GetFile()->GetFullPath(fullPath);
|
||||
mRequest->Resolve(fullPath);
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TFileDescriptorResponse:
|
||||
{
|
||||
DS_LOG_INFO("fd %u", mRequest->GetId());
|
||||
FileDescriptorResponse r = aValue;
|
||||
|
||||
DeviceStorageFile* file = mRequest->GetFile();
|
||||
DeviceStorageFileDescriptor* descriptor = mRequest->GetFileDescriptor();
|
||||
nsString fullPath;
|
||||
mDSFile->GetFullPath(fullPath);
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
StringToJsval(window, fullPath, &result);
|
||||
|
||||
mDSFileDescriptor->mDSFile = mDSFile;
|
||||
mDSFileDescriptor->mFileDescriptor = r.fileDescriptor();
|
||||
mRequest->FireSuccess(result);
|
||||
file->GetFullPath(fullPath);
|
||||
descriptor->mDSFile = file;
|
||||
descriptor->mFileDescriptor = r.fileDescriptor();
|
||||
mRequest->Resolve(fullPath);
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TBlobResponse:
|
||||
{
|
||||
DS_LOG_INFO("blob %u", mRequest->GetId());
|
||||
BlobResponse r = aValue;
|
||||
BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
|
||||
nsRefPtr<BlobImpl> bloblImpl = actor->GetBlobImpl();
|
||||
nsRefPtr<Blob> blob = Blob::Create(mRequest->GetParentObject(),
|
||||
bloblImpl);
|
||||
|
||||
AutoJSContext cx;
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, blob->WrapObject(cx, nullptr));
|
||||
MOZ_ASSERT(obj);
|
||||
|
||||
JS::Rooted<JS::Value> result(cx, JS::ObjectValue(*obj));
|
||||
mRequest->FireSuccess(result);
|
||||
nsRefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
|
||||
mRequest->Resolve(blobImpl.get());
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TFreeSpaceStorageResponse:
|
||||
{
|
||||
DS_LOG_INFO("free %u", mRequest->GetId());
|
||||
FreeSpaceStorageResponse r = aValue;
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx, JS_NumberValue(double(r.freeBytes())));
|
||||
mRequest->FireSuccess(result);
|
||||
mRequest->Resolve(r.freeBytes());
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TUsedSpaceStorageResponse:
|
||||
{
|
||||
DS_LOG_INFO("used %u", mRequest->GetId());
|
||||
UsedSpaceStorageResponse r = aValue;
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx, JS_NumberValue(double(r.usedBytes())));
|
||||
mRequest->FireSuccess(result);
|
||||
mRequest->Resolve(r.usedBytes());
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TAvailableStorageResponse:
|
||||
{
|
||||
DS_LOG_INFO("available %u", mRequest->GetId());
|
||||
AvailableStorageResponse r = aValue;
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
StringToJsval(window, r.mountState(), &result);
|
||||
mRequest->FireSuccess(result);
|
||||
mRequest->Resolve(r.mountState());
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TStorageStatusResponse:
|
||||
{
|
||||
DS_LOG_INFO("status %u", mRequest->GetId());
|
||||
StorageStatusResponse r = aValue;
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
StringToJsval(window, r.storageStatus(), &result);
|
||||
mRequest->FireSuccess(result);
|
||||
mRequest->Resolve(r.storageStatus());
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TFormatStorageResponse:
|
||||
{
|
||||
DS_LOG_INFO("format %u", mRequest->GetId());
|
||||
FormatStorageResponse r = aValue;
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
StringToJsval(window, r.mountState(), &result);
|
||||
mRequest->FireSuccess(result);
|
||||
mRequest->Resolve(r.mountState());
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TMountStorageResponse:
|
||||
{
|
||||
DS_LOG_INFO("mount %u", mRequest->GetId());
|
||||
MountStorageResponse r = aValue;
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
StringToJsval(window, r.storageStatus(), &result);
|
||||
mRequest->FireSuccess(result);
|
||||
mRequest->Resolve(r.storageStatus());
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TUnmountStorageResponse:
|
||||
{
|
||||
DS_LOG_INFO("unmount %u", mRequest->GetId());
|
||||
UnmountStorageResponse r = aValue;
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
StringToJsval(window, r.storageStatus(), &result);
|
||||
mRequest->FireSuccess(result);
|
||||
mRequest->Resolve(r.storageStatus());
|
||||
break;
|
||||
}
|
||||
|
||||
case DeviceStorageResponseValue::TEnumerationResponse:
|
||||
{
|
||||
DS_LOG_INFO("enumerate %u", mRequest->GetId());
|
||||
EnumerationResponse r = aValue;
|
||||
nsDOMDeviceStorageCursor* cursor
|
||||
= static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
|
||||
|
||||
auto request = static_cast<DeviceStorageCursorRequest*>(mRequest.get());
|
||||
uint32_t count = r.paths().Length();
|
||||
cursor->mFiles.SetCapacity(count);
|
||||
request->AddFiles(count);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
nsRefPtr<DeviceStorageFile> dsf
|
||||
= new DeviceStorageFile(r.type(), r.paths()[i].storageName(),
|
||||
r.rootdir(), r.paths()[i].name());
|
||||
cursor->mFiles.AppendElement(dsf.forget());
|
||||
request->AddFile(dsf.forget());
|
||||
}
|
||||
|
||||
nsRefPtr<ContinueCursorEvent> event = new ContinueCursorEvent(cursor);
|
||||
event->Continue();
|
||||
request->Continue();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
DS_LOG_ERROR("unknown %u", mRequest->GetId());
|
||||
NS_RUNTIMEABORT("not reached");
|
||||
break;
|
||||
}
|
||||
|
@ -215,13 +162,6 @@ DeviceStorageRequestChild::
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DeviceStorageRequestChild::
|
||||
SetCallback(DeviceStorageRequestChildCallback *aCallback)
|
||||
{
|
||||
mCallback = aCallback;
|
||||
}
|
||||
|
||||
} // namespace devicestorage
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -10,13 +10,12 @@
|
|||
#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
|
||||
|
||||
class DeviceStorageFile;
|
||||
class DeviceStorageRequest;
|
||||
struct DeviceStorageFileDescriptor;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DOMRequest;
|
||||
|
||||
namespace devicestorage {
|
||||
|
||||
class DeviceStorageRequestChildCallback
|
||||
|
@ -29,21 +28,13 @@ class DeviceStorageRequestChild : public PDeviceStorageRequestChild
|
|||
{
|
||||
public:
|
||||
DeviceStorageRequestChild();
|
||||
DeviceStorageRequestChild(DOMRequest* aRequest, DeviceStorageFile* aFile);
|
||||
DeviceStorageRequestChild(DOMRequest* aRequest, DeviceStorageFile* aFile,
|
||||
DeviceStorageFileDescriptor* aFileDescrptor);
|
||||
explicit DeviceStorageRequestChild(DeviceStorageRequest* aRequest);
|
||||
~DeviceStorageRequestChild();
|
||||
|
||||
void SetCallback(class DeviceStorageRequestChildCallback *aCallback);
|
||||
|
||||
virtual bool Recv__delete__(const DeviceStorageResponseValue& value);
|
||||
|
||||
private:
|
||||
nsRefPtr<DOMRequest> mRequest;
|
||||
nsRefPtr<DeviceStorageFile> mDSFile;
|
||||
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
|
||||
|
||||
DeviceStorageRequestChildCallback* mCallback;
|
||||
nsRefPtr<DeviceStorageRequest> mRequest;
|
||||
};
|
||||
|
||||
} // namespace devicestorage
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,6 +8,7 @@
|
|||
#define nsDeviceStorage_h
|
||||
|
||||
class nsPIDOMWindow;
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
|
||||
|
@ -18,7 +19,6 @@ class nsPIDOMWindow;
|
|||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
@ -36,13 +36,18 @@ namespace mozilla {
|
|||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
class Blob;
|
||||
class BlobImpl;
|
||||
class DeviceStorageParams;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class nsDOMDeviceStorage;
|
||||
class DeviceStorageCursorRequest;
|
||||
|
||||
//#define DS_LOGGING 1
|
||||
|
||||
#ifdef DS_LOGGING
|
||||
// FIXME -- use MOZ_LOG and set to warn by default
|
||||
#define DS_LOG_DEBUG(msg, ...) printf_stderr("[%s:%d] " msg "\n", __func__, __LINE__, ##__VA_ARGS__)
|
||||
#define DS_LOG_INFO DS_LOG_DEBUG
|
||||
#define DS_LOG_WARN DS_LOG_DEBUG
|
||||
|
@ -62,20 +67,29 @@ class Blob;
|
|||
#define POST_ERROR_EVENT_UNKNOWN "Unknown"
|
||||
|
||||
enum DeviceStorageRequestType {
|
||||
DEVICE_STORAGE_REQUEST_READ,
|
||||
DEVICE_STORAGE_REQUEST_WRITE,
|
||||
DEVICE_STORAGE_REQUEST_APPEND,
|
||||
DEVICE_STORAGE_REQUEST_CREATE,
|
||||
DEVICE_STORAGE_REQUEST_DELETE,
|
||||
DEVICE_STORAGE_REQUEST_WATCH,
|
||||
DEVICE_STORAGE_REQUEST_FREE_SPACE,
|
||||
DEVICE_STORAGE_REQUEST_USED_SPACE,
|
||||
DEVICE_STORAGE_REQUEST_AVAILABLE,
|
||||
DEVICE_STORAGE_REQUEST_STATUS,
|
||||
DEVICE_STORAGE_REQUEST_FORMAT,
|
||||
DEVICE_STORAGE_REQUEST_MOUNT,
|
||||
DEVICE_STORAGE_REQUEST_UNMOUNT,
|
||||
DEVICE_STORAGE_REQUEST_CREATEFD
|
||||
DEVICE_STORAGE_REQUEST_READ,
|
||||
DEVICE_STORAGE_REQUEST_WRITE,
|
||||
DEVICE_STORAGE_REQUEST_APPEND,
|
||||
DEVICE_STORAGE_REQUEST_CREATE,
|
||||
DEVICE_STORAGE_REQUEST_DELETE,
|
||||
DEVICE_STORAGE_REQUEST_WATCH,
|
||||
DEVICE_STORAGE_REQUEST_FREE_SPACE,
|
||||
DEVICE_STORAGE_REQUEST_USED_SPACE,
|
||||
DEVICE_STORAGE_REQUEST_AVAILABLE,
|
||||
DEVICE_STORAGE_REQUEST_STATUS,
|
||||
DEVICE_STORAGE_REQUEST_FORMAT,
|
||||
DEVICE_STORAGE_REQUEST_MOUNT,
|
||||
DEVICE_STORAGE_REQUEST_UNMOUNT,
|
||||
DEVICE_STORAGE_REQUEST_CREATEFD,
|
||||
DEVICE_STORAGE_REQUEST_CURSOR
|
||||
};
|
||||
|
||||
enum DeviceStorageAccessType {
|
||||
DEVICE_STORAGE_ACCESS_READ,
|
||||
DEVICE_STORAGE_ACCESS_WRITE,
|
||||
DEVICE_STORAGE_ACCESS_CREATE,
|
||||
DEVICE_STORAGE_ACCESS_UNDEFINED,
|
||||
DEVICE_STORAGE_ACCESS_COUNT
|
||||
};
|
||||
|
||||
class DeviceStorageUsedSpaceCache final
|
||||
|
@ -176,14 +190,17 @@ public:
|
|||
|
||||
void InitFromBundle(nsIStringBundle* aBundle);
|
||||
|
||||
bool Check(const nsAString& aType, mozilla::dom::Blob* aBlob);
|
||||
bool Check(const nsAString& aType, mozilla::dom::BlobImpl* aBlob);
|
||||
bool Check(const nsAString& aType, nsIFile* aFile);
|
||||
bool Check(const nsAString& aType, const nsString& aPath);
|
||||
void GetTypeFromFile(nsIFile* aFile, nsAString& aType);
|
||||
void GetTypeFromFileName(const nsAString& aFileName, nsAString& aType);
|
||||
|
||||
static nsresult GetPermissionForType(const nsAString& aType, nsACString& aPermissionResult);
|
||||
static nsresult GetAccessForRequest(const DeviceStorageRequestType aRequestType, nsACString& aAccessResult);
|
||||
static nsresult GetPermissionForType(const nsAString& aType,
|
||||
nsACString& aPermissionResult);
|
||||
static nsresult GetAccessForRequest(const DeviceStorageRequestType aRequestType,
|
||||
nsACString& aAccessResult);
|
||||
static nsresult GetAccessForIndex(size_t aAccessIndex, nsACString& aAccessResult);
|
||||
static size_t GetAccessIndexForRequest(const DeviceStorageRequestType aRequestType);
|
||||
static bool IsVolumeBased(const nsAString& aType);
|
||||
static bool IsSharedMediaRoot(const nsAString& aType);
|
||||
|
||||
|
@ -195,65 +212,224 @@ private:
|
|||
static mozilla::StaticAutoPtr<DeviceStorageTypeChecker> sDeviceStorageTypeChecker;
|
||||
};
|
||||
|
||||
class ContinueCursorEvent final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit ContinueCursorEvent(already_AddRefed<mozilla::dom::DOMRequest> aRequest);
|
||||
explicit ContinueCursorEvent(mozilla::dom::DOMRequest* aRequest);
|
||||
~ContinueCursorEvent();
|
||||
void Continue();
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
private:
|
||||
already_AddRefed<DeviceStorageFile> GetNextFile();
|
||||
nsRefPtr<mozilla::dom::DOMRequest> mRequest;
|
||||
};
|
||||
|
||||
class nsDOMDeviceStorageCursor final
|
||||
: public mozilla::dom::DOMCursor
|
||||
, public nsIContentPermissionRequest
|
||||
, public mozilla::dom::devicestorage::DeviceStorageRequestChildCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
NS_FORWARD_NSIDOMDOMCURSOR(mozilla::dom::DOMCursor::)
|
||||
|
||||
// DOMCursor
|
||||
virtual void Continue(mozilla::ErrorResult& aRv) override;
|
||||
|
||||
nsDOMDeviceStorageCursor(nsPIDOMWindow* aWindow,
|
||||
nsIPrincipal* aPrincipal,
|
||||
DeviceStorageFile* aFile,
|
||||
PRTime aSince);
|
||||
nsDOMDeviceStorageCursor(nsIGlobalObject* aGlobal,
|
||||
DeviceStorageCursorRequest* aRequest);
|
||||
|
||||
|
||||
nsTArray<nsRefPtr<DeviceStorageFile> > mFiles;
|
||||
bool mOkToCallContinue;
|
||||
PRTime mSince;
|
||||
size_t mIndex;
|
||||
|
||||
void GetStorageType(nsAString & aType);
|
||||
|
||||
void RequestComplete() override;
|
||||
void FireSuccess(JS::Handle<JS::Value> aResult);
|
||||
void FireError(const nsString& aReason);
|
||||
void FireDone();
|
||||
|
||||
private:
|
||||
~nsDOMDeviceStorageCursor();
|
||||
virtual ~nsDOMDeviceStorageCursor();
|
||||
|
||||
nsRefPtr<DeviceStorageFile> mFile;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIContentPermissionRequester> mRequester;
|
||||
bool mOkToCallContinue;
|
||||
nsRefPtr<DeviceStorageCursorRequest> mRequest;
|
||||
};
|
||||
|
||||
//helpers
|
||||
bool
|
||||
StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString,
|
||||
JS::MutableHandle<JS::Value> result);
|
||||
class DeviceStorageRequestManager final
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceStorageRequestManager)
|
||||
|
||||
JS::Value
|
||||
nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile);
|
||||
static const uint32_t INVALID_ID = 0;
|
||||
|
||||
JS::Value
|
||||
InterfaceToJsval(nsPIDOMWindow* aWindow, nsISupports* aObject, const nsIID* aIID);
|
||||
DeviceStorageRequestManager();
|
||||
|
||||
bool IsOwningThread();
|
||||
nsresult DispatchToOwningThread(nsIRunnable* aRunnable);
|
||||
|
||||
void StorePermission(size_t aAccess, bool aAllow);
|
||||
uint32_t CheckPermission(size_t aAccess);
|
||||
|
||||
/* These must be called on the owning thread context of the device
|
||||
storage object. It will hold onto a device storage reference until
|
||||
all of the pending requests are completed or shutdown is called. */
|
||||
uint32_t Create(nsDOMDeviceStorage* aDeviceStorage,
|
||||
mozilla::dom::DOMRequest** aRequest);
|
||||
uint32_t Create(nsDOMDeviceStorage* aDeviceStorage,
|
||||
DeviceStorageCursorRequest* aRequest,
|
||||
nsDOMDeviceStorageCursor** aCursor);
|
||||
|
||||
/* These may be called from any thread context and post a request
|
||||
to the owning thread to resolve the underlying DOMRequest or
|
||||
DOMCursor. In order to trigger FireDone for a DOMCursor, one
|
||||
should call Resolve with only the request ID. */
|
||||
nsresult Resolve(uint32_t aId, bool aForceDispatch);
|
||||
nsresult Resolve(uint32_t aId, const nsString& aValue, bool aForceDispatch);
|
||||
nsresult Resolve(uint32_t aId, uint64_t aValue, bool aForceDispatch);
|
||||
nsresult Resolve(uint32_t aId, DeviceStorageFile* aValue, bool aForceDispatch);
|
||||
nsresult Resolve(uint32_t aId, mozilla::dom::BlobImpl* aValue, bool aForceDispatch);
|
||||
nsresult Reject(uint32_t aId, const nsString& aReason);
|
||||
nsresult Reject(uint32_t aId, const char* aReason);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
DeviceStorageRequestManager(const DeviceStorageRequestManager&) = delete;
|
||||
DeviceStorageRequestManager& operator=(const DeviceStorageRequestManager&) = delete;
|
||||
|
||||
struct ListEntry {
|
||||
nsRefPtr<mozilla::dom::DOMRequest> mRequest;
|
||||
uint32_t mId;
|
||||
bool mCursor;
|
||||
};
|
||||
|
||||
typedef nsTArray<ListEntry> ListType;
|
||||
typedef ListType::index_type ListIndex;
|
||||
|
||||
virtual ~DeviceStorageRequestManager();
|
||||
uint32_t CreateInternal(mozilla::dom::DOMRequest* aRequest, bool aCursor);
|
||||
nsresult ResolveInternal(ListIndex aIndex, JS::HandleValue aResult);
|
||||
nsresult RejectInternal(ListIndex aIndex, const nsString& aReason);
|
||||
nsresult DispatchOrAbandon(uint32_t aId, nsIRunnable* aRunnable);
|
||||
ListType::index_type Find(uint32_t aId);
|
||||
|
||||
nsCOMPtr<nsIThread> mOwningThread;
|
||||
ListType mPending; // owning thread or destructor only
|
||||
|
||||
mozilla::Mutex mMutex;
|
||||
uint32_t mPermissionCache[DEVICE_STORAGE_ACCESS_COUNT];
|
||||
bool mShutdown;
|
||||
|
||||
static mozilla::Atomic<uint32_t> sLastRequestId;
|
||||
};
|
||||
|
||||
class DeviceStorageRequest
|
||||
: public nsRunnable
|
||||
{
|
||||
protected:
|
||||
DeviceStorageRequest();
|
||||
|
||||
public:
|
||||
virtual void Initialize(DeviceStorageRequestManager* aManager,
|
||||
DeviceStorageFile* aFile,
|
||||
uint32_t aRequest);
|
||||
|
||||
virtual void Initialize(DeviceStorageRequestManager* aManager,
|
||||
DeviceStorageFile* aFile,
|
||||
uint32_t aRequest,
|
||||
mozilla::dom::BlobImpl* aBlob);
|
||||
|
||||
virtual void Initialize(DeviceStorageRequestManager* aManager,
|
||||
DeviceStorageFile* aFile,
|
||||
uint32_t aRequest,
|
||||
DeviceStorageFileDescriptor* aDSFileDescriptor);
|
||||
|
||||
DeviceStorageAccessType GetAccess() const;
|
||||
void GetStorageType(nsAString& aType) const;
|
||||
DeviceStorageFile* GetFile() const;
|
||||
DeviceStorageFileDescriptor* GetFileDescriptor() const;
|
||||
DeviceStorageRequestManager* GetManager() const;
|
||||
|
||||
uint32_t GetId() const
|
||||
{
|
||||
return mId;
|
||||
}
|
||||
|
||||
void PermissionCacheMissed()
|
||||
{
|
||||
mPermissionCached = false;
|
||||
}
|
||||
|
||||
nsresult Cancel();
|
||||
nsresult Allow();
|
||||
|
||||
nsresult Resolve()
|
||||
{
|
||||
/* Always dispatch an empty resolve because that signals a cursor end
|
||||
and should not be executed directly from the caller's context due
|
||||
to the object potentially getting freed before we return. */
|
||||
uint32_t id = mId;
|
||||
mId = DeviceStorageRequestManager::INVALID_ID;
|
||||
return mManager->Resolve(id, true);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
nsresult Resolve(T aValue)
|
||||
{
|
||||
uint32_t id = mId;
|
||||
if (!mMultipleResolve) {
|
||||
mId = DeviceStorageRequestManager::INVALID_ID;
|
||||
}
|
||||
return mManager->Resolve(id, aValue, ForceDispatch());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
nsresult Reject(T aReason)
|
||||
{
|
||||
uint32_t id = mId;
|
||||
mId = DeviceStorageRequestManager::INVALID_ID;
|
||||
return mManager->Reject(id, aReason);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool ForceDispatch() const
|
||||
{
|
||||
return !mSendToParent && mPermissionCached;
|
||||
}
|
||||
|
||||
virtual ~DeviceStorageRequest();
|
||||
virtual void Prepare();
|
||||
virtual nsresult CreateSendParams(mozilla::dom::DeviceStorageParams& aParams);
|
||||
nsresult AllowInternal();
|
||||
nsresult SendToParentProcess();
|
||||
|
||||
nsRefPtr<DeviceStorageRequestManager> mManager;
|
||||
nsRefPtr<DeviceStorageFile> mFile;
|
||||
uint32_t mId;
|
||||
nsRefPtr<mozilla::dom::BlobImpl> mBlob;
|
||||
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
|
||||
DeviceStorageAccessType mAccess;
|
||||
bool mSendToParent;
|
||||
bool mUseStreamTransport;
|
||||
bool mCheckFile;
|
||||
bool mCheckBlob;
|
||||
bool mMultipleResolve;
|
||||
bool mPermissionCached;
|
||||
|
||||
private:
|
||||
DeviceStorageRequest(const DeviceStorageRequest&) = delete;
|
||||
DeviceStorageRequest& operator=(const DeviceStorageRequest&) = delete;
|
||||
};
|
||||
|
||||
class DeviceStorageCursorRequest final
|
||||
: public DeviceStorageRequest
|
||||
{
|
||||
public:
|
||||
DeviceStorageCursorRequest();
|
||||
|
||||
using DeviceStorageRequest::Initialize;
|
||||
|
||||
virtual void Initialize(DeviceStorageRequestManager* aManager,
|
||||
DeviceStorageFile* aFile,
|
||||
uint32_t aRequest,
|
||||
PRTime aSince);
|
||||
|
||||
void AddFiles(size_t aSize);
|
||||
void AddFile(already_AddRefed<DeviceStorageFile> aFile);
|
||||
nsresult Continue();
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
protected:
|
||||
virtual ~DeviceStorageCursorRequest()
|
||||
{ };
|
||||
|
||||
nsresult SendContinueToParentProcess();
|
||||
nsresult CreateSendParams(mozilla::dom::DeviceStorageParams& aParams) override;
|
||||
|
||||
size_t mIndex;
|
||||
PRTime mSince;
|
||||
nsString mStorageType;
|
||||
nsTArray<nsRefPtr<DeviceStorageFile> > mFiles;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/TimelineConsumers.h"
|
||||
#include "mozilla/EventTimelineMarker.h"
|
||||
|
||||
#include "EventListenerService.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
@ -1056,29 +1057,6 @@ EventListenerManager::GetDocShellForTarget()
|
|||
return docShell;
|
||||
}
|
||||
|
||||
class EventTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
EventTimelineMarker(nsDocShell* aDocShell, TracingMetadata aMetaData,
|
||||
uint16_t aPhase, const nsAString& aCause)
|
||||
: TimelineMarker(aDocShell, "DOMEvent", aMetaData, aCause)
|
||||
, mPhase(aPhase)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx,
|
||||
mozilla::dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
if (GetMetaData() == TRACING_INTERVAL_START) {
|
||||
aMarker.mType.Construct(GetCause());
|
||||
aMarker.mEventPhase.Construct(mPhase);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t mPhase;
|
||||
};
|
||||
|
||||
/**
|
||||
* Causes a check for event listeners and processing by them if they exist.
|
||||
* @param an event listener
|
||||
|
@ -1149,9 +1127,8 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
|||
(*aDOMEvent)->GetType(typeStr);
|
||||
uint16_t phase;
|
||||
(*aDOMEvent)->GetEventPhase(&phase);
|
||||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<EventTimelineMarker>(ds, TRACING_INTERVAL_START,
|
||||
phase, typeStr);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<EventTimelineMarker>(
|
||||
typeStr, phase, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(ds, Move(marker));
|
||||
}
|
||||
}
|
||||
|
@ -1163,7 +1140,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
|||
|
||||
if (isTimelineRecording) {
|
||||
nsDocShell* ds = static_cast<nsDocShell*>(docShell.get());
|
||||
TimelineConsumers::AddMarkerForDocShell(ds, "DOMEvent", TRACING_INTERVAL_END);
|
||||
TimelineConsumers::AddMarkerForDocShell(ds, "DOMEvent", MarkerTracingType::END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1409,6 +1409,18 @@ ContentChild::RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId)
|
||||
{
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
NS_WARN_IF(!service);
|
||||
|
||||
NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PCrashReporterChild*
|
||||
ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
|
||||
const uint32_t& processType)
|
||||
|
|
|
@ -276,6 +276,7 @@ public:
|
|||
virtual bool DeallocPPresentationChild(PPresentationChild* aActor) override;
|
||||
virtual bool RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
|
||||
const nsString& aSessionId) override;
|
||||
virtual bool RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId) override;
|
||||
|
||||
virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild() override;
|
||||
virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor) override;
|
||||
|
|
|
@ -659,6 +659,12 @@ child:
|
|||
*/
|
||||
async NotifyPresentationReceiverLaunched(PBrowser aIframe, nsString aSessionId);
|
||||
|
||||
/**
|
||||
* Notify the child that the info about a presentation receiver needs to be
|
||||
* cleaned up.
|
||||
*/
|
||||
async NotifyPresentationReceiverCleanUp(nsString aSessionId);
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Tell the content process some attributes of itself. This is
|
||||
|
|
|
@ -81,7 +81,7 @@ Presentation::Init()
|
|||
// session instance is ready at beginning because the web content may access
|
||||
// it right away; whereas the sender doesn't until |startSession| succeeds.
|
||||
nsAutoString sessionId;
|
||||
rv = service->GetExistentSessionIdAtLaunch(sessionId);
|
||||
rv = service->GetExistentSessionIdAtLaunch(GetOwner()->WindowID(), sessionId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -116,13 +116,19 @@ PresentationResponderLoadingCallback::Init(nsIDocShell* aDocShell)
|
|||
nsresult
|
||||
PresentationResponderLoadingCallback::NotifyReceiverReady()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mProgress);
|
||||
if (NS_WARN_IF(!window || !window->GetCurrentInnerWindow())) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
uint64_t windowId = window->GetCurrentInnerWindow()->WindowID();
|
||||
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return service->NotifyReceiverReady(mSessionId);
|
||||
return service->NotifyReceiverReady(mSessionId, windowId);
|
||||
}
|
||||
|
||||
// nsIWebProgressListener
|
||||
|
|
|
@ -221,6 +221,7 @@ PresentationService::HandleShutdown()
|
|||
|
||||
mListeners.Clear();
|
||||
mSessionInfo.Clear();
|
||||
mRespondingSessionIds.Clear();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
|
@ -305,24 +306,11 @@ PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aReques
|
|||
}
|
||||
#endif
|
||||
|
||||
// Make sure the service is not handling another session request.
|
||||
if (NS_WARN_IF(!mRespondingSessionId.IsEmpty())) {
|
||||
ctrlChannel->Close(NS_ERROR_DOM_INUSE_ATTRIBUTE_ERR);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Set |mRespondingSessionId| to indicate the service is handling a session
|
||||
// request. Then a session instance will be prepared while instantiating
|
||||
// |navigator.presentation| at receiver side. This variable will be reset when
|
||||
// registering the session listener.
|
||||
mRespondingSessionId = sessionId;
|
||||
|
||||
// Create or reuse session info.
|
||||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(sessionId);
|
||||
if (NS_WARN_IF(info)) {
|
||||
// TODO Update here after session resumption becomes supported.
|
||||
ctrlChannel->Close(NS_ERROR_DOM_ABORT_ERR);
|
||||
mRespondingSessionId.Truncate();
|
||||
return NS_ERROR_DOM_ABORT_ERR;
|
||||
}
|
||||
|
||||
|
@ -330,7 +318,6 @@ PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aReques
|
|||
rv = info->Init(ctrlChannel);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ctrlChannel->Close(NS_ERROR_DOM_ABORT_ERR);
|
||||
mRespondingSessionId.Truncate();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -483,10 +470,6 @@ PresentationService::RegisterSessionListener(const nsAString& aSessionId,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aListener);
|
||||
|
||||
if (mRespondingSessionId.Equals(aSessionId)) {
|
||||
mRespondingSessionId.Truncate();
|
||||
}
|
||||
|
||||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
// Notify the listener of TERMINATED since no correspondent session info is
|
||||
|
@ -512,30 +495,73 @@ PresentationService::UnregisterSessionListener(const nsAString& aSessionId)
|
|||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
|
||||
if (info) {
|
||||
NS_WARN_IF(NS_FAILED(info->Close(NS_OK)));
|
||||
RemoveSessionInfo(aSessionId);
|
||||
UntrackSessionInfo(aSessionId);
|
||||
return info->SetListener(nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::GetExistentSessionIdAtLaunch(nsAString& aSessionId)
|
||||
PresentationService::GetExistentSessionIdAtLaunch(uint64_t aWindowId,
|
||||
nsAString& aSessionId)
|
||||
{
|
||||
aSessionId = mRespondingSessionId;
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsString* sessionId = mRespondingSessionIds.Get(aWindowId);
|
||||
if (sessionId) {
|
||||
aSessionId.Assign(*sessionId);
|
||||
} else {
|
||||
aSessionId.Truncate();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::NotifyReceiverReady(const nsAString& aSessionId)
|
||||
PresentationService::NotifyReceiverReady(const nsAString& aSessionId,
|
||||
uint64_t aWindowId)
|
||||
{
|
||||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Only track the responding info when an actual window ID, which would never
|
||||
// be 0, is provided (for an in-process receiver page).
|
||||
if (aWindowId != 0) {
|
||||
mRespondingSessionIds.Put(aWindowId, new nsAutoString(aSessionId));
|
||||
mRespondingWindowIds.Put(aSessionId, aWindowId);
|
||||
}
|
||||
|
||||
return static_cast<PresentationResponderInfo*>(info.get())->NotifyResponderReady();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::UntrackSessionInfo(const nsAString& aSessionId)
|
||||
{
|
||||
// Remove the session info.
|
||||
mSessionInfo.Remove(aSessionId);
|
||||
|
||||
// Remove the in-process responding info if there's still any.
|
||||
uint64_t windowId = 0;
|
||||
if(mRespondingWindowIds.Get(aSessionId, &windowId)) {
|
||||
mRespondingWindowIds.Remove(aSessionId);
|
||||
mRespondingSessionIds.Remove(windowId);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
PresentationService::IsSessionAccessible(const nsAString& aSessionId,
|
||||
base::ProcessId aProcessId)
|
||||
{
|
||||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return false;
|
||||
}
|
||||
return info->IsAccessible(aProcessId);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIPresentationService>
|
||||
NS_CreatePresentationService()
|
||||
{
|
||||
|
|
|
@ -38,15 +38,8 @@ public:
|
|||
info.forget() : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
RemoveSessionInfo(const nsAString& aSessionId)
|
||||
{
|
||||
if (mRespondingSessionId.Equals(aSessionId)) {
|
||||
mRespondingSessionId.Truncate();
|
||||
}
|
||||
|
||||
mSessionInfo.Remove(aSessionId);
|
||||
}
|
||||
bool IsSessionAccessible(const nsAString& aSessionId,
|
||||
base::ProcessId aProcessId);
|
||||
|
||||
private:
|
||||
~PresentationService();
|
||||
|
@ -57,9 +50,16 @@ private:
|
|||
bool IsAppInstalled(nsIURI* aUri);
|
||||
|
||||
bool mIsAvailable;
|
||||
nsString mRespondingSessionId;
|
||||
nsRefPtrHashtable<nsStringHashKey, PresentationSessionInfo> mSessionInfo;
|
||||
nsTObserverArray<nsCOMPtr<nsIPresentationListener>> mListeners;
|
||||
|
||||
// Store the mapping between the window ID of the in-process page and the ID
|
||||
// of the responding session. It's used for an in-process receiver page to
|
||||
// retrieve the correspondent session ID. Besides, also keep the mapping
|
||||
// between the responding session ID and the window ID to help look up the
|
||||
// window ID.
|
||||
nsClassHashtable<nsUint64HashKey, nsString> mRespondingSessionIds;
|
||||
nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -192,10 +192,17 @@ PresentationSessionInfo::Close(nsresult aReason)
|
|||
{
|
||||
// The session is disconnected and it's a normal close. Simply change the
|
||||
// state to TERMINATED.
|
||||
if (!IsSessionReady() && NS_SUCCEEDED(aReason) && mListener) {
|
||||
nsresult rv = mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
if (!IsSessionReady() && NS_SUCCEEDED(aReason)) {
|
||||
if (mListener) {
|
||||
// Notify the listener and the service will untrack the session info after
|
||||
// the listener calls |UnregisterSessionListener|.
|
||||
nsresult rv = mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
} else {
|
||||
// Directly untrack the session info from the service.
|
||||
NS_WARN_IF(NS_FAILED(UntrackFromService()));
|
||||
}
|
||||
}
|
||||
|
||||
Shutdown(aReason);
|
||||
|
@ -231,16 +238,29 @@ PresentationSessionInfo::ReplyError(nsresult aError)
|
|||
}
|
||||
|
||||
// Remove itself since it never succeeds.
|
||||
return UntrackFromService();
|
||||
}
|
||||
|
||||
/* virtual */ nsresult
|
||||
PresentationSessionInfo::UntrackFromService()
|
||||
{
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
static_cast<PresentationService*>(service.get())->RemoveSessionInfo(mSessionId);
|
||||
static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
PresentationSessionInfo::IsAccessible(base::ProcessId aProcessId)
|
||||
{
|
||||
// No restriction by default.
|
||||
return true;
|
||||
}
|
||||
|
||||
// nsIPresentationSessionTransportCallback
|
||||
NS_IMETHODIMP
|
||||
PresentationSessionInfo::NotifyTransportReady()
|
||||
|
@ -280,12 +300,17 @@ PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
|
|||
|
||||
Shutdown(aReason);
|
||||
|
||||
uint16_t state = (NS_WARN_IF(NS_FAILED(aReason))) ?
|
||||
nsIPresentationSessionListener::STATE_DISCONNECTED :
|
||||
nsIPresentationSessionListener::STATE_TERMINATED;
|
||||
if (mListener) {
|
||||
// It happens after the session is ready. Notify session state change.
|
||||
uint16_t state = (NS_WARN_IF(NS_FAILED(aReason))) ?
|
||||
nsIPresentationSessionListener::STATE_DISCONNECTED :
|
||||
nsIPresentationSessionListener::STATE_TERMINATED;
|
||||
// If the new state is TERMINATED. the service will untrack the session info
|
||||
// after the listener calls |UnregisterSessionListener|.
|
||||
return mListener->NotifyStateChange(mSessionId, state);
|
||||
} else if (state == nsIPresentationSessionListener::STATE_TERMINATED) {
|
||||
// Directly untrack the session info from the service.
|
||||
return UntrackFromService();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -639,6 +664,34 @@ PresentationResponderInfo::InitTransportAndSendAnswer()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationResponderInfo::UntrackFromService()
|
||||
{
|
||||
// Remove the OOP responding info (if it has never been used).
|
||||
if (mContentParent) {
|
||||
NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverCleanUp(mSessionId));
|
||||
}
|
||||
|
||||
// Remove the session info (and the in-process responding info if there's any).
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
PresentationResponderInfo::IsAccessible(base::ProcessId aProcessId)
|
||||
{
|
||||
// Only the specific content process should access the responder info.
|
||||
return (mContentParent) ?
|
||||
aProcessId == static_cast<ContentParent*>(mContentParent.get())->OtherPid() :
|
||||
false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationResponderInfo::NotifyResponderReady()
|
||||
{
|
||||
|
@ -774,8 +827,10 @@ PresentationResponderInfo::ResolvedCallback(JSContext* aCx,
|
|||
nsRefPtr<TabParent> tabParent = TabParent::GetFrom(frameLoader);
|
||||
if (tabParent) {
|
||||
// OOP frame
|
||||
nsCOMPtr<nsIContentParent> cp = tabParent->Manager();
|
||||
NS_WARN_IF(!static_cast<ContentParent*>(cp.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId));
|
||||
// Notify the content process that a receiver page has launched, so it can
|
||||
// start monitoring the loading progress.
|
||||
mContentParent = tabParent->Manager();
|
||||
NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId));
|
||||
} else {
|
||||
// In-process frame
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
|
@ -785,6 +840,7 @@ PresentationResponderInfo::ResolvedCallback(JSContext* aCx,
|
|||
return;
|
||||
}
|
||||
|
||||
// Keep an eye on the loading progress of the receiver page.
|
||||
mLoadingCallback = new PresentationResponderLoadingCallback(mSessionId);
|
||||
rv = mLoadingCallback->Init(docShell);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef mozilla_dom_PresentationSessionInfo_h
|
||||
#define mozilla_dom_PresentationSessionInfo_h
|
||||
|
||||
#include "base/process.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
|
@ -92,6 +93,8 @@ public:
|
|||
|
||||
nsresult ReplyError(nsresult aReason);
|
||||
|
||||
virtual bool IsAccessible(base::ProcessId aProcessId);
|
||||
|
||||
protected:
|
||||
virtual ~PresentationSessionInfo()
|
||||
{
|
||||
|
@ -107,6 +110,8 @@ protected:
|
|||
return mIsResponderReady && mIsTransportReady;
|
||||
}
|
||||
|
||||
virtual nsresult UntrackFromService();
|
||||
|
||||
nsString mUrl;
|
||||
nsString mSessionId;
|
||||
bool mIsResponderReady;
|
||||
|
@ -184,6 +189,8 @@ public:
|
|||
mPromise->AppendNativeHandler(this);
|
||||
}
|
||||
|
||||
bool IsAccessible(base::ProcessId aProcessId) override;
|
||||
|
||||
private:
|
||||
~PresentationResponderInfo()
|
||||
{
|
||||
|
@ -194,10 +201,16 @@ private:
|
|||
|
||||
nsresult InitTransportAndSendAnswer();
|
||||
|
||||
nsresult UntrackFromService() override;
|
||||
|
||||
nsRefPtr<PresentationResponderLoadingCallback> mLoadingCallback;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsCOMPtr<nsIPresentationChannelDescription> mRequesterDescription;
|
||||
nsRefPtr<Promise> mPromise;
|
||||
|
||||
// The content parent communicating with the content process which the OOP
|
||||
// receiver page belongs to.
|
||||
nsCOMPtr<nsIContentParent> mContentParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -32,7 +32,7 @@ interface nsIPresentationServiceCallback : nsISupports
|
|||
void notifyError(in nsresult error);
|
||||
};
|
||||
|
||||
[scriptable, uuid(5801efd9-9dba-4af7-8be9-8fc97c2d54a6)]
|
||||
[scriptable, uuid(731af98a-2760-4e7f-bb59-c7cf6665f26f)]
|
||||
interface nsIPresentationService : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -99,14 +99,29 @@ interface nsIPresentationService : nsISupports
|
|||
|
||||
/*
|
||||
* Check if the presentation instance has an existent session ID at launch.
|
||||
* An empty string is returned at sender side; non-empty at receiver side.
|
||||
* An empty string is always returned at sender side. Whereas at receiver side
|
||||
* the associated session ID is returned if the window ID and URI are matched;
|
||||
* otherwise an empty string is returned.
|
||||
*
|
||||
* @param windowId: The inner window ID used to look up the session ID.
|
||||
*/
|
||||
DOMString getExistentSessionIdAtLaunch();
|
||||
DOMString getExistentSessionIdAtLaunch(in uint64_t windowId);
|
||||
|
||||
/*
|
||||
* Notify the receiver page is ready for presentation use.
|
||||
*
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
* @param windowId: The inner window ID associated with the presentation
|
||||
* session. (0 implies no window ID since no actual window
|
||||
* uses 0 as its ID.)
|
||||
*/
|
||||
void notifyReceiverReady(in DOMString sessionId);
|
||||
void notifyReceiverReady(in DOMString sessionId,
|
||||
[optional] in uint64_t windowId);
|
||||
|
||||
/*
|
||||
* Untrack the relevant info about the presentation session if there's any.
|
||||
*
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
*/
|
||||
void untrackSessionInfo(in DOMString sessionId);
|
||||
};
|
||||
|
|
|
@ -58,9 +58,6 @@ parent:
|
|||
|
||||
PPresentationRequest(PresentationRequest aRequest);
|
||||
|
||||
sync GetExistentSessionIdAtLaunch()
|
||||
returns (nsString aSessionId);
|
||||
|
||||
NotifyReceiverReady(nsString aSessionId);
|
||||
};
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ PresentationIPCService::~PresentationIPCService()
|
|||
{
|
||||
mListeners.Clear();
|
||||
mSessionListeners.Clear();
|
||||
mRespondingSessionIds.Clear();
|
||||
mRespondingWindowIds.Clear();
|
||||
sPresentationChild = nullptr;
|
||||
}
|
||||
|
||||
|
@ -130,6 +132,8 @@ PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
UntrackSessionInfo(aSessionId);
|
||||
|
||||
mSessionListeners.Remove(aSessionId);
|
||||
if (sPresentationChild) {
|
||||
NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsAutoString(aSessionId)));
|
||||
|
@ -174,26 +178,53 @@ PresentationIPCService::NotifyAvailableChange(bool aAvailable)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::GetExistentSessionIdAtLaunch(nsAString& aSessionId)
|
||||
PresentationIPCService::GetExistentSessionIdAtLaunch(uint64_t aWindowId,
|
||||
nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsAutoString sessionId(aSessionId);
|
||||
NS_WARN_IF(!sPresentationChild->SendGetExistentSessionIdAtLaunch(&sessionId));
|
||||
aSessionId = sessionId;
|
||||
|
||||
nsString* sessionId = mRespondingSessionIds.Get(aWindowId);
|
||||
if (sessionId) {
|
||||
aSessionId.Assign(*sessionId);
|
||||
} else {
|
||||
aSessionId.Truncate();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId)
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId,
|
||||
uint64_t aWindowId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// No actual window uses 0 as its ID.
|
||||
if (NS_WARN_IF(aWindowId == 0)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Track the responding info for an OOP receiver page.
|
||||
mRespondingSessionIds.Put(aWindowId, new nsAutoString(aSessionId));
|
||||
mRespondingWindowIds.Put(aSessionId, aWindowId);
|
||||
|
||||
mCallback = nullptr;
|
||||
NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsAutoString(aSessionId)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::UntrackSessionInfo(const nsAString& aSessionId)
|
||||
{
|
||||
// Remove the OOP responding info (if it has never been used).
|
||||
uint64_t windowId = 0;
|
||||
if(mRespondingWindowIds.Get(aSessionId, &windowId)) {
|
||||
mRespondingWindowIds.Remove(aSessionId);
|
||||
mRespondingSessionIds.Remove(windowId);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
PresentationIPCService::NotifyPresentationChildDestroyed()
|
||||
{
|
||||
|
@ -204,6 +235,8 @@ nsresult
|
|||
PresentationIPCService::MonitorResponderLoading(const nsAString& aSessionId,
|
||||
nsIDocShell* aDocShell)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mCallback = new PresentationResponderLoadingCallback(aSessionId);
|
||||
return mCallback->Init(aDocShell);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,14 @@ private:
|
|||
nsTObserverArray<nsCOMPtr<nsIPresentationListener> > mListeners;
|
||||
nsRefPtrHashtable<nsStringHashKey, nsIPresentationSessionListener> mSessionListeners;
|
||||
nsRefPtr<PresentationResponderLoadingCallback> mCallback;
|
||||
|
||||
// Store the mapping between the window ID of the OOP page (in this process)
|
||||
// and the ID of the responding session. It's used for an OOP receiver page
|
||||
// to retrieve the correspondent session ID. Besides, also keep the mapping
|
||||
// between the responding session ID and the window ID to help look up the
|
||||
// window ID.
|
||||
nsClassHashtable<nsUint64HashKey, nsString> mRespondingSessionIds;
|
||||
nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -120,6 +120,14 @@ PresentationParent::RecvUnregisterHandler()
|
|||
PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
// Validate the accessibility (primarily for receiver side) so that a
|
||||
// compromised child process can't fake the ID.
|
||||
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
|
||||
IsSessionAccessible(aSessionId, OtherPid()))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mSessionIds.AppendElement(aSessionId);
|
||||
NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, this)));
|
||||
return true;
|
||||
|
@ -148,7 +156,7 @@ PresentationParent::NotifyStateChange(const nsAString& aSessionId,
|
|||
uint16_t aState)
|
||||
{
|
||||
if (NS_WARN_IF(mActorDestroyed ||
|
||||
!SendNotifySessionStateChange(nsString(aSessionId), aState))) {
|
||||
!SendNotifySessionStateChange(nsAutoString(aSessionId), aState))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -159,25 +167,17 @@ PresentationParent::NotifyMessage(const nsAString& aSessionId,
|
|||
const nsACString& aData)
|
||||
{
|
||||
if (NS_WARN_IF(mActorDestroyed ||
|
||||
!SendNotifyMessage(nsString(aSessionId), nsCString(aData)))) {
|
||||
!SendNotifyMessage(nsAutoString(aSessionId), nsAutoCString(aData)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
PresentationParent::RecvGetExistentSessionIdAtLaunch(nsString* aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
NS_WARN_IF(NS_FAILED(mService->GetExistentSessionIdAtLaunch(*aSessionId)));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId)));
|
||||
NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId, 0)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -218,6 +218,14 @@ nsresult
|
|||
PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
// Validate the accessibility (primarily for receiver side) so that a
|
||||
// compromised child process can't fake the ID.
|
||||
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
|
||||
IsSessionAccessible(aRequest.sessionId(), OtherPid()))) {
|
||||
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
|
||||
nsTArray<mozilla::ipc::FileDescriptor> fds;
|
||||
nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aRequest.data(), fds);
|
||||
if(NS_WARN_IF(!stream)) {
|
||||
|
@ -235,6 +243,14 @@ nsresult
|
|||
PresentationRequestParent::DoRequest(const TerminateRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
// Validate the accessibility (primarily for receiver side) so that a
|
||||
// compromised child process can't fake the ID.
|
||||
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
|
||||
IsSessionAccessible(aRequest.sessionId(), OtherPid()))) {
|
||||
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
|
||||
nsresult rv = mService->Terminate(aRequest.sessionId());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NotifyError(rv);
|
||||
|
|
|
@ -50,8 +50,6 @@ public:
|
|||
|
||||
virtual bool RecvUnregisterSessionHandler(const nsString& aSessionId) override;
|
||||
|
||||
virtual bool RecvGetExistentSessionIdAtLaunch(nsString* aSessionId) override;
|
||||
|
||||
virtual bool RecvNotifyReceiverReady(const nsString& aSessionId) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for B2G Presentation Session API on a non-receiver page at receiver side (OOP)</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
"use strict";
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK ' : 'KO ') + msg);
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK ' : 'KO ') + msg);
|
||||
}
|
||||
|
||||
function info(msg) {
|
||||
alert('INFO ' + msg);
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function testSessionAvailable() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
ok(navigator.presentation, "navigator.presentation should be available in OOP pages.");
|
||||
ok(!navigator.presentation.session, "Non-receiving OOP pages shouldn't get a predefined presentation session instance.");
|
||||
aResolve();
|
||||
});
|
||||
}
|
||||
|
||||
testSessionAvailable().
|
||||
then(finish);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -4,6 +4,7 @@ support-files =
|
|||
PresentationSessionChromeScript.js
|
||||
file_presentation_receiver.html
|
||||
file_presentation_receiver_oop.html
|
||||
file_presentation_non_receiver_oop.html
|
||||
file_presentation_receiver_start_session_error.html
|
||||
|
||||
[test_presentation_device_info.html]
|
||||
|
|
|
@ -82,6 +82,9 @@ function testIncomingSessionRequest() {
|
|||
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
|
||||
info("Trying to launch receiver page.");
|
||||
|
||||
ok(navigator.presentation, "navigator.presentation should be available in in-process pages.");
|
||||
ok(!navigator.presentation.session, "Non-receiving in-process pages shouldn't get a predefined presentation session instance.");
|
||||
|
||||
aResolve();
|
||||
});
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
|
||||
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver_oop.html');
|
||||
var nonReceiverUrl = SimpleTest.getTestFileURL('file_presentation_non_receiver_oop.html');
|
||||
|
||||
var isReceiverFinished = false;
|
||||
var isNonReceiverFinished = false;
|
||||
|
||||
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIObserverService);
|
||||
|
@ -27,17 +31,17 @@ function setup() {
|
|||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.sendAsyncMessage('trigger-device-add');
|
||||
|
||||
// Create a receiver OOP iframe.
|
||||
SpecialPowers.addPermission('presentation', true, { url: receiverUrl,
|
||||
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
|
||||
isInBrowserElement: true });
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('remote', 'true');
|
||||
iframe.setAttribute('mozbrowser', 'true');
|
||||
iframe.setAttribute('src', receiverUrl);
|
||||
var receiverIframe = document.createElement('iframe');
|
||||
receiverIframe.setAttribute('remote', 'true');
|
||||
receiverIframe.setAttribute('mozbrowser', 'true');
|
||||
receiverIframe.setAttribute('src', receiverUrl);
|
||||
|
||||
// This event is triggered when the iframe calls "alert".
|
||||
iframe.addEventListener('mozbrowsershowmodalprompt', function listener(aEvent) {
|
||||
receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(aEvent) {
|
||||
var message = aEvent.detail.message;
|
||||
if (/^OK /.exec(message)) {
|
||||
ok(true, "Message from iframe: " + message);
|
||||
|
@ -50,19 +54,58 @@ function setup() {
|
|||
gScript.sendAsyncMessage(command.name, command.data);
|
||||
} else if (/^DONE$/.exec(message)) {
|
||||
ok(true, "Messaging from iframe complete.");
|
||||
iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
|
||||
receiverIframe.removeEventListener('mozbrowsershowmodalprompt', receiverListener);
|
||||
|
||||
teardown();
|
||||
isReceiverFinished = true;
|
||||
|
||||
if (isNonReceiverFinished) {
|
||||
teardown();
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
var promise = new Promise(function(aResolve, aReject) {
|
||||
document.body.appendChild(iframe);
|
||||
document.body.appendChild(receiverIframe);
|
||||
|
||||
aResolve(iframe);
|
||||
aResolve(receiverIframe);
|
||||
});
|
||||
obs.notifyObservers(promise, 'setup-request-promise', null);
|
||||
|
||||
// Create a non-receiver OOP iframe.
|
||||
SpecialPowers.addPermission('presentation', true, { url: nonReceiverUrl,
|
||||
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
|
||||
isInBrowserElement: true });
|
||||
var nonReceiverIframe = document.createElement('iframe');
|
||||
nonReceiverIframe.setAttribute('remote', 'true');
|
||||
nonReceiverIframe.setAttribute('mozbrowser', 'true');
|
||||
nonReceiverIframe.setAttribute('src', nonReceiverUrl);
|
||||
|
||||
// This event is triggered when the iframe calls "alert".
|
||||
nonReceiverIframe.addEventListener('mozbrowsershowmodalprompt', function nonReceiverListener(aEvent) {
|
||||
var message = aEvent.detail.message;
|
||||
if (/^OK /.exec(message)) {
|
||||
ok(true, "Message from iframe: " + message);
|
||||
} else if (/^KO /.exec(message)) {
|
||||
ok(false, "Message from iframe: " + message);
|
||||
} else if (/^INFO /.exec(message)) {
|
||||
info("Message from iframe: " + message);
|
||||
} else if (/^COMMAND /.exec(message)) {
|
||||
var command = JSON.parse(message.replace(/^COMMAND /, ''));
|
||||
gScript.sendAsyncMessage(command.name, command.data);
|
||||
} else if (/^DONE$/.exec(message)) {
|
||||
ok(true, "Messaging from iframe complete.");
|
||||
nonReceiverIframe.removeEventListener('mozbrowsershowmodalprompt', nonReceiverListener);
|
||||
|
||||
isNonReceiverFinished = true;
|
||||
|
||||
if (isReceiverFinished) {
|
||||
teardown();
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.body.appendChild(nonReceiverIframe);
|
||||
|
||||
gScript.addMessageListener('offer-received', function offerReceivedHandler() {
|
||||
gScript.removeMessageListener('offer-received', offerReceivedHandler);
|
||||
info("An offer is received.");
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "nsPrintfCString.h"
|
||||
#include "nsRenderingContext.h"
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
#include "mozilla/LayerTimelineMarker.h"
|
||||
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/ReverseIterator.h"
|
||||
|
@ -5497,36 +5498,6 @@ static void DrawForcedBackgroundColor(DrawTarget& aDrawTarget,
|
|||
}
|
||||
}
|
||||
|
||||
class LayerTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
LayerTimelineMarker(nsDocShell* aDocShell, const nsIntRegion& aRegion)
|
||||
: TimelineMarker(aDocShell, "Layer", TRACING_EVENT)
|
||||
, mRegion(aRegion)
|
||||
{
|
||||
}
|
||||
|
||||
~LayerTimelineMarker()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void AddLayerRectangles(mozilla::dom::Sequence<mozilla::dom::ProfileTimelineLayerRect>& aRectangles) override
|
||||
{
|
||||
nsIntRegionRectIterator it(mRegion);
|
||||
while (const nsIntRect* iterRect = it.Next()) {
|
||||
mozilla::dom::ProfileTimelineLayerRect rect;
|
||||
rect.mX = iterRect->X();
|
||||
rect.mY = iterRect->Y();
|
||||
rect.mWidth = iterRect->Width();
|
||||
rect.mHeight = iterRect->Height();
|
||||
aRectangles.AppendElement(rect, fallible);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsIntRegion mRegion;
|
||||
};
|
||||
|
||||
/*
|
||||
* A note on residual transforms:
|
||||
*
|
||||
|
@ -5687,8 +5658,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
|
|||
bool isRecording;
|
||||
docShell->GetRecordProfileTimelineMarkers(&isRecording);
|
||||
if (isRecording) {
|
||||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<LayerTimelineMarker>(docShell, aRegionToDraw);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<LayerTimelineMarker>(aRegionToDraw);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ struct EventRadiusPrefs
|
|||
bool mRepositionEventCoords;
|
||||
bool mTouchClusterDetectionEnabled;
|
||||
uint32_t mLimitReadableSize;
|
||||
uint32_t mKeepLimitSizeForCluster;
|
||||
};
|
||||
|
||||
static EventRadiusPrefs sMouseEventRadiusPrefs;
|
||||
|
@ -130,6 +131,9 @@ GetPrefsFor(EventClassID aEventClassID)
|
|||
|
||||
nsPrintfCString limitReadableSizePref("ui.zoomedview.limitReadableSize", prefBranch);
|
||||
Preferences::AddUintVarCache(&prefs->mLimitReadableSize, limitReadableSizePref.get(), 8);
|
||||
|
||||
nsPrintfCString keepLimitSize("ui.zoomedview.keepLimitSize", prefBranch);
|
||||
Preferences::AddUintVarCache(&prefs->mKeepLimitSizeForCluster, keepLimitSize.get(), 16);
|
||||
}
|
||||
|
||||
return prefs;
|
||||
|
@ -356,6 +360,21 @@ static bool IsElementPresent(nsTArray<nsIFrame*>& aCandidates, const nsAutoStrin
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsLargeElement(nsIFrame* aFrame, const EventRadiusPrefs* aPrefs)
|
||||
{
|
||||
uint32_t keepLimitSizeForCluster = aPrefs->mKeepLimitSizeForCluster;
|
||||
nsSize frameSize = aFrame->GetSize();
|
||||
nsPresContext* pc = aFrame->PresContext();
|
||||
nsIPresShell* presShell = pc->PresShell();
|
||||
float cumulativeResolution = presShell->GetCumulativeResolution();
|
||||
if ((pc->AppUnitsToGfxUnits(frameSize.height) * cumulativeResolution) > keepLimitSizeForCluster &&
|
||||
(pc->AppUnitsToGfxUnits(frameSize.width) * cumulativeResolution) > keepLimitSizeForCluster) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame,
|
||||
const nsRect& aTargetRect, const EventRadiusPrefs* aPrefs,
|
||||
|
@ -413,7 +432,8 @@ GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame,
|
|||
// and "for" attribute is present in label element, search the frame list for the "for" element
|
||||
// If this element is present in the current list, do not count the frame in
|
||||
// the cluster elements counter
|
||||
if (labelTargetId.IsEmpty() || !IsElementPresent(aCandidates, labelTargetId)) {
|
||||
if ((labelTargetId.IsEmpty() || !IsElementPresent(aCandidates, labelTargetId)) &&
|
||||
!IsLargeElement(f, aPrefs)) {
|
||||
if (std::find(mContentsInCluster.begin(), mContentsInCluster.end(), clickableContent) == mContentsInCluster.end()) {
|
||||
mContentsInCluster.push_back(clickableContent);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "RestyleManager.h"
|
||||
#include "RestyleTrackerInlines.h"
|
||||
#include "nsTransitionManager.h"
|
||||
#include "mozilla/RestyleTimelineMarker.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -97,31 +98,6 @@ struct RestyleCollector {
|
|||
#endif
|
||||
};
|
||||
|
||||
class RestyleTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
RestyleTimelineMarker(nsDocShell* aDocShell,
|
||||
TracingMetadata aMetaData,
|
||||
nsRestyleHint aRestyleHint)
|
||||
: TimelineMarker(aDocShell, "Styles", aMetaData)
|
||||
{
|
||||
if (aRestyleHint) {
|
||||
mRestyleHint.AssignWithConversion(RestyleManager::RestyleHintToString(aRestyleHint));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx,
|
||||
mozilla::dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
if (GetMetaData() == TRACING_INTERVAL_START) {
|
||||
aMarker.mRestyleHint.Construct(mRestyleHint);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoString mRestyleHint;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
CollectRestyles(nsISupports* aElement,
|
||||
nsAutoPtr<RestyleTracker::RestyleData>& aData,
|
||||
|
@ -358,10 +334,8 @@ RestyleTracker::DoProcessRestyles()
|
|||
}
|
||||
|
||||
if (isTimelineRecording) {
|
||||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<RestyleTimelineMarker>(docShell,
|
||||
TRACING_INTERVAL_START,
|
||||
data->mRestyleHint);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
|
||||
data->mRestyleHint, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
}
|
||||
|
||||
|
@ -376,10 +350,8 @@ RestyleTracker::DoProcessRestyles()
|
|||
AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
|
||||
|
||||
if (isTimelineRecording) {
|
||||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<RestyleTimelineMarker>(docShell,
|
||||
TRACING_INTERVAL_END,
|
||||
data->mRestyleHint);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
|
||||
data->mRestyleHint, MarkerTracingType::END);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
}
|
||||
}
|
||||
|
@ -423,10 +395,8 @@ RestyleTracker::DoProcessRestyles()
|
|||
}
|
||||
#endif
|
||||
if (isTimelineRecording) {
|
||||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<RestyleTimelineMarker>(docShell,
|
||||
TRACING_INTERVAL_START,
|
||||
currentRestyle->mRestyleHint);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
|
||||
currentRestyle->mRestyleHint, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
}
|
||||
|
||||
|
@ -436,10 +406,8 @@ RestyleTracker::DoProcessRestyles()
|
|||
currentRestyle->mRestyleHintData);
|
||||
|
||||
if (isTimelineRecording) {
|
||||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<RestyleTimelineMarker>(docShell,
|
||||
TRACING_INTERVAL_END,
|
||||
currentRestyle->mRestyleHint);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
|
||||
currentRestyle->mRestyleHint, MarkerTracingType::END);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8983,7 +8983,7 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
|
|||
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
|
||||
if (docShell) {
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", TRACING_INTERVAL_START);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::START);
|
||||
}
|
||||
|
||||
if (mReflowContinueTimer) {
|
||||
|
@ -9160,7 +9160,7 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
|
|||
}
|
||||
|
||||
if (docShell) {
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", TRACING_INTERVAL_END);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::END);
|
||||
}
|
||||
return !interrupted;
|
||||
}
|
||||
|
|
|
@ -1708,7 +1708,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
|||
for (nsDocShell* docShell : profilingDocShells) {
|
||||
// For the sake of the profile timeline's simplicity, this is flagged as
|
||||
// paint even if it includes creating display lists
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", TRACING_INTERVAL_START);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::START);
|
||||
}
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
|
||||
|
@ -1725,7 +1725,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
|||
}
|
||||
#endif
|
||||
for (nsDocShell* docShell : profilingDocShells) {
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", TRACING_INTERVAL_END);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::END);
|
||||
}
|
||||
|
||||
if (nsContentUtils::XPConnect()) {
|
||||
|
|
|
@ -415,6 +415,7 @@ pref("font.size.inflation.minTwips", 0);
|
|||
pref("browser.ui.zoom.force-user-scalable", false);
|
||||
|
||||
pref("ui.zoomedview.enabled", true);
|
||||
pref("ui.zoomedview.keepLimitSize", 16); // value in layer pixels, used to not keep the large elements in the cluster list (Bug 1191041)
|
||||
pref("ui.zoomedview.limitReadableSize", 8); // value in layer pixels
|
||||
pref("ui.zoomedview.defaultZoomFactor", 2);
|
||||
pref("ui.zoomedview.simplified", true); // Do not display all the zoomed view controls
|
||||
|
|
|
@ -241,7 +241,7 @@ public class ZoomedView extends FrameLayout implements LayerView.DynamicToolbarL
|
|||
touchListener = new ZoomedViewTouchListener();
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener(this,
|
||||
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange",
|
||||
"Gesture:CloseZoomedView");
|
||||
"Gesture:CloseZoomedView", "Browser:ZoomToPageWidth", "Browser:ZoomToRect");
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
|
@ -250,7 +250,7 @@ public class ZoomedView extends FrameLayout implements LayerView.DynamicToolbarL
|
|||
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
|
||||
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange",
|
||||
"Gesture:CloseZoomedView");
|
||||
"Gesture:CloseZoomedView", "Browser:ZoomToPageWidth", "Browser:ZoomToRect");
|
||||
}
|
||||
|
||||
// This method (onFinishInflate) is called only when the zoomed view class is used inside
|
||||
|
@ -562,8 +562,13 @@ public class ZoomedView extends FrameLayout implements LayerView.DynamicToolbarL
|
|||
}
|
||||
|
||||
public void stopZoomDisplay(boolean withAnimation) {
|
||||
// If "startZoomDisplay" is running and not totally completed (Gecko thread is still
|
||||
// running and "showZoomedView" has not yet been called), the zoomed view will be
|
||||
// displayed after this call and it should not.
|
||||
// Force the stop of the zoomed view, changing the shouldSetVisibleOnUpdate flag
|
||||
// before the test of the visibility.
|
||||
shouldSetVisibleOnUpdate = false;
|
||||
if (getVisibility() == View.VISIBLE) {
|
||||
shouldSetVisibleOnUpdate = false;
|
||||
hideZoomedView(withAnimation);
|
||||
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
|
||||
if (layerView != null) {
|
||||
|
@ -616,7 +621,9 @@ public class ZoomedView extends FrameLayout implements LayerView.DynamicToolbarL
|
|||
refreshZoomedViewSize(metrics);
|
||||
} else if (event.equals("Content:LocationChange")) {
|
||||
stopZoomDisplay(false);
|
||||
} else if (event.equals("Gesture:CloseZoomedView")) {
|
||||
} else if (event.equals("Gesture:CloseZoomedView") ||
|
||||
event.equals("Browser:ZoomToPageWidth") ||
|
||||
event.equals("Browser:ZoomToRect")) {
|
||||
stopZoomDisplay(true);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
|
|
|
@ -123,13 +123,24 @@ this.Async = {
|
|||
Services.obs.addObserver(function onQuitApplication() {
|
||||
Services.obs.removeObserver(onQuitApplication, "quit-application");
|
||||
Async.checkAppReady = function() {
|
||||
throw Components.Exception("App. Quitting", Cr.NS_ERROR_ABORT);
|
||||
let exception = Components.Exception("App. Quitting", Cr.NS_ERROR_ABORT);
|
||||
exception.appIsShuttingDown = true;
|
||||
throw exception;
|
||||
};
|
||||
}, "quit-application", false);
|
||||
// In the common case, checkAppReady just returns true
|
||||
return (Async.checkAppReady = function() { return true; })();
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the passed exception is one raised by checkAppReady. Typically
|
||||
* this will be used in exception handlers to allow such exceptions to
|
||||
* make their way to the top frame and allow the app to actually terminate.
|
||||
*/
|
||||
isShutdownException(exception) {
|
||||
return exception && exception.appIsShuttingDown === true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the two things you need to make an asynchronous call synchronous
|
||||
* by spinning the event loop.
|
||||
|
|
|
@ -667,7 +667,7 @@ this.BrowserIDManager.prototype = {
|
|||
this._ensureValidToken().then(cb, cb);
|
||||
try {
|
||||
cb.wait();
|
||||
} catch (ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
this._log.error("Failed to fetch a token for authentication", ex);
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -307,7 +307,7 @@ Store.prototype = {
|
|||
// originating exception.
|
||||
// ex.cause will carry its stack with it when rethrown.
|
||||
throw ex.cause;
|
||||
} catch (ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
this._log.warn("Failed to apply incoming record " + record.id);
|
||||
this._log.warn("Encountered exception: " + Utils.exceptionStr(ex));
|
||||
failed.push(record.id);
|
||||
|
@ -992,7 +992,7 @@ SyncEngine.prototype = {
|
|||
this._tracker.ignoreAll = true;
|
||||
try {
|
||||
failed = failed.concat(this._store.applyIncomingBatch(applyBatch));
|
||||
} catch (ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
// Catch any error that escapes from applyIncomingBatch. At present
|
||||
// those will all be abort events.
|
||||
this._log.warn("Got exception " + Utils.exceptionStr(ex) +
|
||||
|
@ -1086,7 +1086,7 @@ SyncEngine.prototype = {
|
|||
self._log.warn("Reconciliation failed: aborting incoming processing.");
|
||||
failed.push(item.id);
|
||||
aborting = ex.cause;
|
||||
} catch (ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
self._log.warn("Failed to reconcile incoming record " + item.id);
|
||||
self._log.warn("Encountered exception: " + Utils.exceptionStr(ex));
|
||||
failed.push(item.id);
|
||||
|
@ -1458,8 +1458,7 @@ SyncEngine.prototype = {
|
|||
|
||||
out.encrypt(this.service.collectionKeys.keyForCollection(this.name));
|
||||
up.pushData(out);
|
||||
}
|
||||
catch(ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
this._log.warn("Error creating record: " + Utils.exceptionStr(ex));
|
||||
}
|
||||
|
||||
|
@ -1550,8 +1549,7 @@ SyncEngine.prototype = {
|
|||
try {
|
||||
this._log.trace("Trying to decrypt a record from the server..");
|
||||
test.get();
|
||||
}
|
||||
catch(ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
this._log.debug("Failed test decrypt: " + Utils.exceptionStr(ex));
|
||||
}
|
||||
|
||||
|
|
|
@ -256,7 +256,7 @@ BookmarksEngine.prototype = {
|
|||
stmt.params.id = id;
|
||||
let rows = Async.querySpinningly(stmt, ["url"]);
|
||||
url = rows.length == 0 ? "<not found>" : rows[0].url;
|
||||
} catch (ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
if (ex instanceof Ci.mozIStorageError) {
|
||||
url = `<failed: Storage error: ${ex.message} (${ex.result})>`;
|
||||
} else {
|
||||
|
@ -441,7 +441,7 @@ BookmarksEngine.prototype = {
|
|||
let guidMap;
|
||||
try {
|
||||
guidMap = this._buildGUIDMap();
|
||||
} catch (ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
this._log.warn("Got exception \"" + Utils.exceptionStr(ex) +
|
||||
"\" building GUID map." +
|
||||
" Skipping all other incoming items.");
|
||||
|
|
|
@ -222,7 +222,7 @@ HistoryStore.prototype = {
|
|||
} else {
|
||||
shouldApply = this._recordToPlaceInfo(record);
|
||||
}
|
||||
} catch(ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
failed.push(record.id);
|
||||
shouldApply = false;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ Cu.import("resource://services-sync/record.js");
|
|||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-sync/engines.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
|
||||
this.LoginRec = function LoginRec(collection, id) {
|
||||
CryptoWrapper.call(this, collection, id);
|
||||
|
@ -67,7 +68,7 @@ PasswordEngine.prototype = {
|
|||
// record success.
|
||||
Svc.Prefs.set("deletePwdFxA", true);
|
||||
Svc.Prefs.reset("deletePwd"); // The old prefname we previously used.
|
||||
} catch (ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
this._log.debug("Password deletes failed: " + Utils.exceptionStr(ex));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ Cu.import("resource://gre/modules/Promise.jsm");
|
|||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
|
||||
// Lazy import to prevent unnecessary load on startup.
|
||||
for (let symbol of ["BulkKeyBundle", "SyncKeyBundle"]) {
|
||||
|
@ -457,7 +458,7 @@ IdentityManager.prototype = {
|
|||
// cache.
|
||||
try {
|
||||
service.recordManager.get(service.storageURL + "meta/fxa_credentials");
|
||||
} catch (ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
this._log.warn("Failed to pre-fetch the migration sentinel", ex);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -23,6 +23,7 @@ Cu.import("resource://services-sync/constants.js");
|
|||
Cu.import("resource://services-sync/keys.js");
|
||||
Cu.import("resource://services-sync/resource.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
|
||||
this.WBORecord = function WBORecord(collection, id) {
|
||||
this.data = {};
|
||||
|
@ -235,7 +236,7 @@ RecordManager.prototype = {
|
|||
record.deserialize(this.response);
|
||||
|
||||
return this.set(url, record);
|
||||
} catch(ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
this._log.debug("Failed to import record: " + Utils.exceptionStr(ex));
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -403,7 +403,7 @@ Resource.prototype = {
|
|||
try {
|
||||
this._doRequest(action, data, callback);
|
||||
return Async.waitForSyncCallback(cb);
|
||||
} catch(ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
// Combine the channel stack with this request stack. Need to create
|
||||
// a new error object for that.
|
||||
let error = Error(ex.message);
|
||||
|
@ -556,7 +556,7 @@ ChannelListener.prototype = {
|
|||
|
||||
try {
|
||||
this._onProgress();
|
||||
} catch (ex) {
|
||||
} catch (ex if !Async.isShutdownException(ex)) {
|
||||
this._log.warn("Got exception calling onProgress handler during fetch of "
|
||||
+ req.URI.spec);
|
||||
this._log.debug(CommonUtils.exceptionStr(ex));
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# XXX Bug 1181261 - Please update config in testing/mozharness/config
|
||||
# instead. This file is still needed for mulet mochitests, but should
|
||||
# be removed once bug 1188330 is finished.
|
||||
# instead. This file is still needed for taskcluster emulator tests,
|
||||
# but should be removed once bug 1188330 is finished.
|
||||
|
||||
config = {
|
||||
"suite_definitions": {
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
# 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/.
|
||||
|
||||
# XXX Bug 1181261 - Please update config in testing/mozharness/config
|
||||
# instead. This file is still needed for taskcluster emulator tests,
|
||||
# but should be removed once bug 1188330 is finished.
|
||||
|
||||
config = {
|
||||
"suite_definitions": {
|
||||
"gaiatest_desktop": {
|
||||
"options": [
|
||||
"--restart",
|
||||
"--timeout=%(timeout)s",
|
||||
"--type=%(type)s",
|
||||
"--testvars=%(testvars)s",
|
||||
"--profile=%(profile)s",
|
||||
"--symbols-path=%(symbols_path)s",
|
||||
"--gecko-log=%(gecko_log)s",
|
||||
"--xml-output=%(xml_output)s",
|
||||
"--html-output=%(html_output)s",
|
||||
"--log-raw=%(raw_log_file)s",
|
||||
"--log-errorsummary=%(error_summary_file)s",
|
||||
"--binary=%(binary)s",
|
||||
"--address=%(address)s",
|
||||
"--total-chunks=%(total_chunks)s",
|
||||
"--this-chunk=%(this_chunk)s"
|
||||
],
|
||||
"run_filename": "",
|
||||
"testsdir": ""
|
||||
},
|
||||
"gaiatest_emulator": {
|
||||
"options": [
|
||||
"--restart",
|
||||
"--timeout=%(timeout)s",
|
||||
"--type=%(type)s",
|
||||
"--testvars=%(testvars)s",
|
||||
"--profile=%(profile)s",
|
||||
"--symbols-path=%(symbols_path)s",
|
||||
"--xml-output=%(xml_output)s",
|
||||
"--html-output=%(html_output)s",
|
||||
"--log-raw=%(raw_log_file)s",
|
||||
"--log-errorsummary=%(error_summary_file)s",
|
||||
"--logcat-dir=%(logcat_dir)s",
|
||||
"--emulator=%(emulator)s",
|
||||
"--homedir=%(homedir)s"
|
||||
],
|
||||
"run_filename": "",
|
||||
"testsdir": ""
|
||||
},
|
||||
"marionette_desktop": {
|
||||
"options": [
|
||||
"--type=%(type)s",
|
||||
"--log-raw=%(raw_log_file)s",
|
||||
"--log-errorsummary=%(error_summary_file)s",
|
||||
"--binary=%(binary)s",
|
||||
"--address=%(address)s",
|
||||
"--symbols-path=%(symbols_path)s"
|
||||
],
|
||||
"run_filename": "",
|
||||
"testsdir": ""
|
||||
},
|
||||
"marionette_emulator": {
|
||||
"options": [
|
||||
"--type=%(type)s",
|
||||
"--log-raw=%(raw_log_file)s",
|
||||
"--log-errorsummary=%(error_summary_file)s",
|
||||
"--logcat-dir=%(logcat_dir)s",
|
||||
"--emulator=%(emulator)s",
|
||||
"--homedir=%(homedir)s",
|
||||
"--symbols-path=%(symbols_path)s"
|
||||
],
|
||||
"run_filename": "",
|
||||
"testsdir": ""
|
||||
},
|
||||
"webapi_desktop": {
|
||||
"options": [],
|
||||
"run_filename": "",
|
||||
"testsdir": ""
|
||||
},
|
||||
"webapi_emulator": {
|
||||
"options": [
|
||||
"--type=%(type)s",
|
||||
"--log-raw=%(raw_log_file)s",
|
||||
"--log-errorsummary=%(error_summary_file)s",
|
||||
"--symbols-path=%(symbols_path)s",
|
||||
"--logcat-dir=%(logcat_dir)s",
|
||||
"--emulator=%(emulator)s",
|
||||
"--homedir=%(homedir)s"
|
||||
],
|
||||
"run_filename": "",
|
||||
"testsdir": ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ RUN git config --global user.email "mozilla@example.com" && \
|
|||
git config --global user.name "mozilla"
|
||||
|
||||
# VCS Tools
|
||||
RUN npm install -g taskcluster-vcs@2.3.8
|
||||
RUN npm install -g taskcluster-vcs@2.3.9
|
||||
|
||||
# TODO enable worker
|
||||
# TODO volume mount permissions will be an issue
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.5.7
|
||||
0.5.8
|
||||
|
|
|
@ -31,7 +31,7 @@ RUN git config --global user.email "mozilla@example.com" && \
|
|||
|
||||
|
||||
# Get node packages
|
||||
RUN npm install -g taskcluster-vcs@2.3.8
|
||||
RUN npm install -g taskcluster-vcs@2.3.9
|
||||
|
||||
WORKDIR /home/worker
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.0.5
|
||||
0.0.6
|
||||
|
|
|
@ -18,7 +18,7 @@ RUN chmod u+x /usr/local/bin/linux64-minidump_stackwalk
|
|||
RUN apt-get install -y python-pip && pip install virtualenv;
|
||||
RUN mkdir Documents; mkdir Pictures; mkdir Music; mkdir Videos; mkdir artifacts
|
||||
RUN npm install -g npm@^2.0.0
|
||||
RUN npm install -g taskcluster-vcs@2.3.8
|
||||
RUN npm install -g taskcluster-vcs@2.3.9
|
||||
RUN npm install -g taskcluster-npm-cache@1.1.14
|
||||
RUN rm -Rf .cache && mkdir -p .cache
|
||||
ENV PATH $PATH:/home/worker/bin
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.3.6
|
||||
0.3.7
|
||||
|
|
|
@ -11,7 +11,7 @@ RUN bash /tmp/system-setup.sh
|
|||
# configure git and install tc-vcs
|
||||
RUN git config --global user.email "nobody@mozilla.com" && \
|
||||
git config --global user.name "mozilla"
|
||||
RUN npm install -g taskcluster-vcs@2.3.8
|
||||
RUN npm install -g taskcluster-vcs@2.3.9
|
||||
|
||||
# Ensure that build specific dependencies live in a single layer
|
||||
ADD build-setup.sh /tmp/build-setup.sh
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче