Merge m-c to inbound a=merge CLOSED TREE

This commit is contained in:
Wes Kocher 2015-04-20 17:16:03 -07:00
Родитель 9becf2d33f 1d3fd84d27
Коммит afda1781f5
64 изменённых файлов: 425 добавлений и 1478 удалений

Просмотреть файл

@ -22,4 +22,8 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1148639 - libvpx update moved a bunch of files around.
Bug 1155718: Merge Bluetooth v1/v2 files for all simple cases
This patch set renames source files. This requires updating the
build system's dependency information from scratch. The issue has
been reported in bug 1154232.

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

Просмотреть файл

@ -19,10 +19,10 @@
<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="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="46e1877c0d88b085f7ebc5f432d5bb8f1e2d1f3b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>

Просмотреть файл

@ -17,7 +17,7 @@
</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="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="c7d4045742862a7cf3f0074902ebc7d1b339b0ee"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -131,7 +131,7 @@
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="f5f7fa2fc26b96d2cbd0af4569c0036fe034bb43"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="fbd2becab3825c49e756db5149552f85049c66e2"/>
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="694cecf256122d0cb3b6a1a4efb4b5c7401db223"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="c0bf1eec60644abbc5e72c251c15092b4c71b6a9"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="0c2ffe181ca64a6cad9c5f93ddea623f080c6434"/>
<project name="platform/development" path="development" revision="5968ff4e13e0d696ad8d972281fc27ae5a12829b"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="0951179277915335251c5e11d242e4e1a8c2236f"/>
<project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="6b0721ca0e92788df30daf8f7a5fb2863544f9c8">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

Просмотреть файл

@ -19,10 +19,10 @@
<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="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="46e1877c0d88b085f7ebc5f432d5bb8f1e2d1f3b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="c7d4045742862a7cf3f0074902ebc7d1b339b0ee"/>

Просмотреть файл

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "cb41d8421da5dc4f16ea566ea2917a9b7f828154",
"git_revision": "a8e4f95dce9db727dda5d408b038f97fb4296557",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "06ea3f1fb3f2706336c6b32d31663db0ec690cd9",
"revision": "b3bc7b2c50201c1110e3f7157d6ed542e52d9355",
"repo_path": "integration/gaia-central"
}

Просмотреть файл

@ -17,7 +17,7 @@
</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="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="c7d4045742862a7cf3f0074902ebc7d1b339b0ee"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="6b0721ca0e92788df30daf8f7a5fb2863544f9c8">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="cb41d8421da5dc4f16ea566ea2917a9b7f828154"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a8e4f95dce9db727dda5d408b038f97fb4296557"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f2f0cbee2f2517070dd194051d509c07cdacff"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

Просмотреть файл

@ -253,7 +253,9 @@ loop.conversationViews = (function(mozL10n) {
onClick: this._handleDecline},
mozL10n.get("incoming_call_cancel_button")
),
React.createElement("div", {className: "btn-chevron", onClick: this.toggleDropdownMenu})
React.createElement("div", {className: "btn-chevron",
onClick: this.toggleDropdownMenu,
ref: "menu-button"})
),
React.createElement("ul", {className: dropdownMenuClassesDecline},

Просмотреть файл

@ -253,7 +253,9 @@ loop.conversationViews = (function(mozL10n) {
onClick={this._handleDecline}>
{mozL10n.get("incoming_call_cancel_button")}
</button>
<div className="btn-chevron" onClick={this.toggleDropdownMenu} />
<div className="btn-chevron"
onClick={this.toggleDropdownMenu}
ref="menu-button" />
</div>
<ul className={dropdownMenuClassesDecline}>

Просмотреть файл

@ -163,7 +163,7 @@ loop.panel = (function(_, mozL10n) {
return (
React.createElement("div", {className: "dropdown"},
React.createElement("p", {className: "dnd-status", onClick: this.showDropdownMenu},
React.createElement("p", {className: "dnd-status", onClick: this.toggleDropdownMenu, ref: "menu-button"},
React.createElement("span", null, availabilityText),
React.createElement("i", {className: availabilityStatus})
),
@ -344,8 +344,10 @@ loop.panel = (function(_, mozL10n) {
return (
React.createElement("div", {className: "settings-menu dropdown"},
React.createElement("a", {className: "button-settings", onClick: this.showDropdownMenu,
title: mozL10n.get("settings_menu_button_tooltip")}),
React.createElement("a", {className: "button-settings",
onClick: this.toggleDropdownMenu,
title: mozL10n.get("settings_menu_button_tooltip"),
ref: "menu-button"}),
React.createElement("ul", {className: cx({"dropdown-menu": true, hide: !this.state.showMenu})},
React.createElement(SettingsDropdownEntry, {label: mozL10n.get("settings_menu_item_settings"),
onClick: this.handleClickSettingsEntry,

Просмотреть файл

@ -163,7 +163,7 @@ loop.panel = (function(_, mozL10n) {
return (
<div className="dropdown">
<p className="dnd-status" onClick={this.showDropdownMenu}>
<p className="dnd-status" onClick={this.toggleDropdownMenu} ref="menu-button">
<span>{availabilityText}</span>
<i className={availabilityStatus}></i>
</p>
@ -344,8 +344,10 @@ loop.panel = (function(_, mozL10n) {
return (
<div className="settings-menu dropdown">
<a className="button-settings" onClick={this.showDropdownMenu}
title={mozL10n.get("settings_menu_button_tooltip")} />
<a className="button-settings"
onClick={this.toggleDropdownMenu}
title={mozL10n.get("settings_menu_button_tooltip")}
ref="menu-button" />
<ul className={cx({"dropdown-menu": true, hide: !this.state.showMenu})}>
<SettingsDropdownEntry label={mozL10n.get("settings_menu_item_settings")}
onClick={this.handleClickSettingsEntry}

Просмотреть файл

@ -94,8 +94,16 @@ loop.shared.mixins = (function() {
return {showMenu: false};
},
_onBodyClick: function() {
this.setState({showMenu: false});
_onBodyClick: function(event) {
var menuButton = this.refs["menu-button"] && this.refs["menu-button"].getDOMNode();
if (this.refs.anchor) {
menuButton = this.refs.anchor.getDOMNode();
}
// If a menu button/ anchor is defined and clicked on, it will be in charge
// of hiding or showing the popup.
if (event.target !== menuButton) {
this.setState({ showMenu: false });
}
},
_correctMenuPosition: function() {

Просмотреть файл

@ -163,6 +163,7 @@ loop.shared.views = (function(_, l10n) {
React.createElement("div", null,
React.createElement("button", {className: screenShareClasses,
onClick: this.handleClick,
ref: "menu-button",
title: this._getTitle()},
isActive ? null : React.createElement("span", {className: "chevron"})
),

Просмотреть файл

@ -163,6 +163,7 @@ loop.shared.views = (function(_, l10n) {
<div>
<button className={screenShareClasses}
onClick={this.handleClick}
ref="menu-button"
title={this._getTitle()}>
{isActive ? null : <span className="chevron"/>}
</button>

Просмотреть файл

@ -20,6 +20,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
@ -42,29 +43,24 @@ function chromeTimeToDate(aTime)
/**
* Insert bookmark items into specific folder.
*
* @param aFolderId
* id of folder where items will be inserted
* @param aItems
* @param parentGuid
* GUID of the folder where items will be inserted
* @param items
* bookmark items to be inserted
*/
function insertBookmarkItems(aFolderId, aItems)
{
for (let i = 0; i < aItems.length; i++) {
let item = aItems[i];
function* insertBookmarkItems(parentGuid, items) {
for (let item of items) {
try {
if (item.type == "url") {
PlacesUtils.bookmarks.insertBookmark(aFolderId,
NetUtil.newURI(item.url),
PlacesUtils.bookmarks.DEFAULT_INDEX,
item.name);
yield PlacesUtils.bookmarks.insert({
parentGuid, url: item.url, title: item.name
});
} else if (item.type == "folder") {
let newFolderId =
PlacesUtils.bookmarks.createFolder(aFolderId,
item.name,
PlacesUtils.bookmarks.DEFAULT_INDEX);
let newFolderGuid = (yield PlacesUtils.bookmarks.insert({
parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title: item.name
})).guid;
insertBookmarkItems(newFolderId, item.children);
yield insertBookmarkItems(newFolderGuid, item.children);
}
} catch (e) {
Cu.reportError(e);
@ -189,48 +185,51 @@ function GetBookmarksResource(aProfileFolder) {
type: MigrationUtils.resourceTypes.BOOKMARKS,
migrate: function(aCallback) {
NetUtil.asyncFetch2(bookmarksFile, MigrationUtils.wrapMigrateFunction(
function(aInputStream, aResultCode) {
if (!Components.isSuccessCode(aResultCode))
throw new Error("Could not read Bookmarks file");
// Parse Chrome bookmark file that is JSON format
let bookmarkJSON = NetUtil.readInputStreamToString(
aInputStream, aInputStream.available(), { charset : "UTF-8" });
let roots = JSON.parse(bookmarkJSON).roots;
PlacesUtils.bookmarks.runInBatchMode({
runBatched: function() {
// Importing bookmark bar items
if (roots.bookmark_bar.children &&
roots.bookmark_bar.children.length > 0) {
// Toolbar
let parentId = PlacesUtils.toolbarFolderId;
if (!MigrationUtils.isStartupMigration) {
parentId = MigrationUtils.createImportedBookmarksFolder(
"Chrome", parentId);
}
insertBookmarkItems(parentId, roots.bookmark_bar.children);
}
return Task.spawn(function* () {
let jsonStream = yield new Promise(resolve =>
NetUtil.asyncFetch({ uri: NetUtil.newURI(bookmarksFile),
loadUsingSystemPrincipal: true
},
(inputStream, resultCode) => {
if (Components.isSuccessCode(resultCode)) {
resolve(inputStream);
} else {
reject(new Error("Could not read Bookmarks file"));
}
}
)
);
// Importing bookmark menu items
if (roots.other.children &&
roots.other.children.length > 0) {
// Bookmark menu
let parentId = PlacesUtils.bookmarksMenuFolderId;
if (!MigrationUtils.isStartupMigration) {
parentId = MigrationUtils.createImportedBookmarksFolder(
"Chrome", parentId);
}
insertBookmarkItems(parentId, roots.other.children);
}
}
}, null);
}, aCallback),
null, // aLoadingNode
Services.scriptSecurityManager.getSystemPrincipal(),
null, // aTriggeringPrincipal
Ci.nsILoadInfo.SEC_NORMAL,
Ci.nsIContentPolicy.TYPE_OTHER);
// Parse Chrome bookmark file that is JSON format
let bookmarkJSON = NetUtil.readInputStreamToString(
jsonStream, jsonStream.available(), { charset : "UTF-8" });
let roots = JSON.parse(bookmarkJSON).roots;
// Importing bookmark bar items
if (roots.bookmark_bar.children &&
roots.bookmark_bar.children.length > 0) {
// Toolbar
let parentGuid = PlacesUtils.bookmarks.toolbarGuid;
if (!MigrationUtils.isStartupMigration) {
parentGuid =
yield MigrationUtils.createImportedBookmarksFolder("Chrome", parentGuid);
}
yield insertBookmarkItems(parentGuid, roots.bookmark_bar.children);
}
// Importing bookmark menu items
if (roots.other.children &&
roots.other.children.length > 0) {
// Bookmark menu
let parentGuid = PlacesUtils.bookmarks.menuGuid;
if (!MigrationUtils.isStartupMigration) {
parentGuid =
yield MigrationUtils.createImportedBookmarksFolder("Chrome", parentGuid);
}
yield insertBookmarkItems(parentGuid, roots.other.children);
}
}.bind(this)).then(() => aCallback(true),
e => { Cu.reportError(e); aCallback(false) });
}
};
}

Просмотреть файл

@ -13,7 +13,7 @@ const kMainKey = "Software\\Microsoft\\Internet Explorer\\Main";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
@ -169,23 +169,19 @@ Bookmarks.prototype = {
},
migrate: function B_migrate(aCallback) {
PlacesUtils.bookmarks.runInBatchMode({
runBatched: (function migrateBatched() {
// Import to the bookmarks menu.
let destFolderId = PlacesUtils.bookmarksMenuFolderId;
if (!MigrationUtils.isStartupMigration) {
destFolderId =
MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
}
this._migrateFolder(this._favoritesFolder, destFolderId);
aCallback(true);
}).bind(this)
}, null);
return Task.spawn(function* () {
// Import to the bookmarks menu.
let folderGuid = PlacesUtils.bookmarks.menuGuid;
if (!MigrationUtils.isStartupMigration) {
folderGuid =
yield MigrationUtils.createImportedBookmarksFolder("IE", folderGuid);
}
yield this._migrateFolder(this._favoritesFolder, folderGuid);
}.bind(this)).then(() => aCallback(true),
e => { Cu.reportError(e); aCallback(false) });
},
_migrateFolder: function B__migrateFolder(aSourceFolder, aDestFolderId) {
_migrateFolder: Task.async(function* (aSourceFolder, aDestFolderGuid) {
// TODO (bug 741993): the favorites order is stored in the Registry, at
// HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites
// Until we support it, bookmarks are imported in alphabetical order.
@ -198,26 +194,28 @@ Bookmarks.prototype = {
// Don't use isSymlink(), since it would throw for invalid
// lnk files pointing to URLs or to unresolvable paths.
if (entry.path == entry.target && entry.isDirectory()) {
let destFolderId;
let folderGuid;
if (entry.leafName == this._toolbarFolderName &&
entry.parent.equals(this._favoritesFolder)) {
// Import to the bookmarks toolbar.
destFolderId = PlacesUtils.toolbarFolderId;
folderGuid = PlacesUtils.bookmarks.toolbarGuid;
if (!MigrationUtils.isStartupMigration) {
destFolderId =
MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
folderGuid =
yield MigrationUtils.createImportedBookmarksFolder("IE", folderGuid);
}
}
else {
// Import to a new folder.
destFolderId =
PlacesUtils.bookmarks.createFolder(aDestFolderId, entry.leafName,
PlacesUtils.bookmarks.DEFAULT_INDEX);
folderGuid = (yield PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_FOLDER,
parentGuid: aDestFolderGuid,
title: entry.leafName
})).guid;
}
if (entry.isReadable()) {
// Recursively import the folder.
this._migrateFolder(entry, destFolderId);
yield this._migrateFolder(entry, folderGuid);
}
}
else {
@ -230,17 +228,16 @@ Bookmarks.prototype = {
let uri = fileHandler.readURLFile(entry);
let title = matches[1];
PlacesUtils.bookmarks.insertBookmark(aDestFolderId,
uri,
PlacesUtils.bookmarks.DEFAULT_INDEX,
title);
yield PlacesUtils.bookmarks.insert({
parentGuid: aDestFolderGuid, url: uri, title
});
}
}
} catch (ex) {
Components.utils.reportError("Unable to import IE favorite (" + entry.leafName + "): " + ex);
}
}
}
})
};
function History() {

Просмотреть файл

@ -15,11 +15,10 @@ const TOPIC_DID_IMPORT_BOOKMARKS = "initial-migration-did-import-default-bookmar
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
"resource://gre/modules/BookmarkHTMLUtils.jsm");
@ -422,23 +421,22 @@ this.MigrationUtils = Object.freeze({
* Helper for creating a folder for imported bookmarks from a particular
* migration source. The folder is created at the end of the given folder.
*
* @param aSourceNameStr
* @param sourceNameStr
* the source name (first letter capitalized). This is used
* for reading the localized source name from the migration
* bundle (e.g. if aSourceNameStr is Mosaic, this will try to read
* sourceNameMosaic from the migration bundle).
* @param aParentId
* the item-id of the folder in which the new folder should be
* created.
* @return the item-id of the new folder.
* @param parentGuid
* the GUID of the folder in which the new folder should be created.
* @return the GUID of the new folder.
*/
createImportedBookmarksFolder:
function MU_createImportedBookmarksFolder(aSourceNameStr, aParentId) {
let source = this.getLocalizedString("sourceName" + aSourceNameStr);
let label = this.getLocalizedString("importedBookmarksFolder", [source]);
return PlacesUtils.bookmarks.createFolder(
aParentId, label, PlacesUtils.bookmarks.DEFAULT_INDEX);
},
createImportedBookmarksFolder: Task.async(function* (sourceNameStr, parentGuid) {
let source = this.getLocalizedString("sourceName" + sourceNameStr);
let title = this.getLocalizedString("importedBookmarksFolder", [source]);
return (yield PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_FOLDER, parentGuid, title
})).guid;
}),
get _migrators() {
return gMigrators ? gMigrators : gMigrators = new Map();

Просмотреть файл

@ -32,23 +32,21 @@ Bookmarks.prototype = {
type: MigrationUtils.resourceTypes.BOOKMARKS,
migrate: function B_migrate(aCallback) {
PropertyListUtils.read(this._file,
MigrationUtils.wrapMigrateFunction(function migrateBookmarks(aDict) {
if (!aDict)
throw new Error("Could not read Bookmarks.plist");
return Task.spawn(function* () {
let dict = yield new Promise(resolve =>
PropertyListUtils.read(this._file, resolve)
);
if (!dict)
throw new Error("Could not read Bookmarks.plist");
let children = dict.get("Children");
if (!children)
throw new Error("Invalid Bookmarks.plist format");
let children = aDict.get("Children");;
if (!children)
throw new Error("Invalid Bookmarks.plist format");
PlacesUtils.bookmarks.runInBatchMode({
runBatched: function() {
let collection = aDict.get("Title") == "com.apple.ReadingList" ?
this.READING_LIST_COLLECTION : this.ROOT_COLLECTION;
this._migrateCollection(children, collection);
}.bind(this)
}, null);
}.bind(this), aCallback));
let collection = dict.get("Title") == "com.apple.ReadingList" ?
this.READING_LIST_COLLECTION : this.ROOT_COLLECTION;
yield this._migrateCollection(children, collection);
}.bind(this)).then(() => aCallback(true),
e => { Cu.reportError(e); aCallback(false) });
},
// Bookmarks collections in Safari. Constants for migrateCollection.
@ -65,7 +63,7 @@ Bookmarks.prototype = {
* @param aCollection
* one of the values above.
*/
_migrateCollection: function B__migrateCollection(aEntries, aCollection) {
_migrateCollection: Task.async(function* (aEntries, aCollection) {
// A collection of bookmarks in Safari resembles places roots. In the
// property list files (Bookmarks.plist, ReadingList.plist) they are
// stored as regular bookmarks folders, and thus can only be distinguished
@ -79,11 +77,11 @@ Bookmarks.prototype = {
let title = entry.get("Title");
let children = entry.get("Children");
if (title == "BookmarksBar")
this._migrateCollection(children, this.TOOLBAR_COLLECTION);
yield this._migrateCollection(children, this.TOOLBAR_COLLECTION);
else if (title == "BookmarksMenu")
this._migrateCollection(children, this.MENU_COLLECTION);
yield this._migrateCollection(children, this.MENU_COLLECTION);
else if (title == "com.apple.ReadingList")
this._migrateCollection(children, this.READING_LIST_COLLECTION);
yield this._migrateCollection(children, this.READING_LIST_COLLECTION);
else if (entry.get("ShouldOmitFromUI") !== true)
entriesFiltered.push(entry);
}
@ -99,7 +97,7 @@ Bookmarks.prototype = {
if (entriesFiltered.length == 0)
return;
let folder = -1;
let folderGuid = -1;
switch (aCollection) {
case this.ROOT_COLLECTION: {
// In Safari, it is possible (though quite cumbersome) to move
@ -108,22 +106,22 @@ Bookmarks.prototype = {
// both the places root and the unfiled-bookmarks root.
// Because the former is only an implementation detail in our UI,
// the unfiled root seems to be the best choice.
folder = PlacesUtils.unfiledBookmarksFolderId;
folderGuid = PlacesUtils.bookmarks.unfiledGuid;
break;
}
case this.MENU_COLLECTION: {
folder = PlacesUtils.bookmarksMenuFolderId;
folderGuid = PlacesUtils.bookmarks.menuGuid;
if (!MigrationUtils.isStartupMigration) {
folder = MigrationUtils.createImportedBookmarksFolder("Safari",
folder);
folderGuid =
yield MigrationUtils.createImportedBookmarksFolder("Safari", folderGuid);
}
break;
}
case this.TOOLBAR_COLLECTION: {
folder = PlacesUtils.toolbarFolderId;
folderGuid = PlacesUtils.bookmarks.toolbarGuid;
if (!MigrationUtils.isStartupMigration) {
folder = MigrationUtils.createImportedBookmarksFolder("Safari",
folder);
folderGuid =
yield MigrationUtils.createImportedBookmarksFolder("Safari", folderGuid);
}
break;
}
@ -131,51 +129,52 @@ Bookmarks.prototype = {
// Reading list items are imported as regular bookmarks.
// They are imported under their own folder, created either under the
// bookmarks menu (in the case of startup migration).
folder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarksMenuFolderId,
MigrationUtils.getLocalizedString("importedSafariReadingList"),
PlacesUtils.bookmarks.DEFAULT_INDEX);
folderGuid = (yield PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.menuGuid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
title: MigrationUtils.getLocalizedString("importedSafariReadingList"),
})).guid;
break;
}
default:
throw new Error("Unexpected value for aCollection!");
}
if (folderGuid == -1)
throw new Error("Invalid folder GUID");
this._migrateEntries(entriesFiltered, folder);
},
yield this._migrateEntries(entriesFiltered, folderGuid);
}),
// migrate the given array of safari bookmarks to the given places
// folder.
_migrateEntries: function B__migrateEntries(aEntries, aFolderId) {
for (let entry of aEntries) {
_migrateEntries: Task.async(function* (entries, parentGuid) {
for (let entry of entries) {
let type = entry.get("WebBookmarkType");
if (type == "WebBookmarkTypeList" && entry.has("Children")) {
let title = entry.get("Title");
let folderId = PlacesUtils.bookmarks.createFolder(
aFolderId, title, PlacesUtils.bookmarks.DEFAULT_INDEX);
let newFolderGuid = (yield PlacesUtils.bookmarks.insert({
parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title
})).guid;
// Empty folders may not have a children array.
if (entry.has("Children"))
this._migrateEntries(entry.get("Children"), folderId, false);
yield this._migrateEntries(entry.get("Children"), newFolderGuid, false);
}
else if (type == "WebBookmarkTypeLeaf" && entry.has("URLString")) {
let title, uri;
let title;
if (entry.has("URIDictionary"))
title = entry.get("URIDictionary").get("title");
try {
uri = NetUtil.newURI(entry.get("URLString"));
}
catch(ex) {
Cu.reportError("Invalid uri set for Safari bookmark: " + entry.get("URLString"));
}
if (uri) {
PlacesUtils.bookmarks.insertBookmark(aFolderId, uri,
PlacesUtils.bookmarks.DEFAULT_INDEX, title);
yield PlacesUtils.bookmarks.insert({
parentGuid, url: entry.get("URLString"), title
});
} catch(ex) {
Cu.reportError("Invalid Safari bookmark: " + ex);
}
}
}
}
})
};
function History(aHistoryFile) {

Двоичный файл не отображается.

Просмотреть файл

@ -35,3 +35,26 @@ function promiseMigration(migrator, resourceType) {
migrator.migrate(resourceType, null, null);
});
}
/**
* Replaces a directory service entry with a given nsIFile.
*/
function registerFakePath(key, file) {
// Register our own provider for the Library directory.
let provider = {
getFile(prop, persistent) {
persistent.value = true;
if (prop == key) {
return file;
}
throw Cr.NS_ERROR_FAILURE;
},
QueryInterface: XPCOMUtils.generateQI([ Ci.nsIDirectoryServiceProvider ])
};
Services.dirsvc.QueryInterface(Ci.nsIDirectoryService)
.registerProvider(provider);
do_register_cleanup(() => {
Services.dirsvc.QueryInterface(Ci.nsIDirectoryService)
.unregisterProvider(provider);
});
}

Просмотреть файл

@ -0,0 +1,37 @@
add_task(function* () {
registerFakePath("ULibDir", do_get_file("Library/"));
let migrator = MigrationUtils.getMigrator("safari");
// Sanity check for the source.
Assert.ok(migrator.sourceExists);
// Wait for the imported bookmarks. Check that "From Safari"
// folders are created on the toolbar.
let source = MigrationUtils.getLocalizedString("sourceNameSafari");
let label = MigrationUtils.getLocalizedString("importedBookmarksFolder", [source]);
let expectedParents = [ PlacesUtils.toolbarFolderId ];
PlacesUtils.bookmarks.addObserver({
onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle) {
if (aTitle == label) {
let index = expectedParents.indexOf(aParentId);
Assert.notEqual(index, -1);
expectedParents.splice(index, 1);
if (expectedParents.length == 0)
PlacesUtils.bookmarks.removeObserver(this);
}
},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onItemRemoved() {},
onItemChanged() {},
onItemVisited() {},
onItemMoved() {},
}, false);
yield promiseMigration(migrator, MigrationUtils.resourceTypes.BOOKMARKS);
// Check the bookmarks have been imported to all the expected parents.
Assert.equal(expectedParents.length, 0);
});

Просмотреть файл

@ -3,9 +3,13 @@ head = head_migration.js
tail =
firefox-appdir = browser
skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
Library/Safari/Bookmarks.plist
[test_fx_fhr.js]
[test_IE_bookmarks.js]
skip-if = os != "win"
[test_IE_cookies.js]
skip-if = os != "win"
[test_Safari_bookmarks.js]
skip-if = os != "mac"

Просмотреть файл

@ -220,7 +220,13 @@ let SessionFileInternal = {
break;
} catch (ex if ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
exists = false;
} catch (ex if ex instanceof OS.File.Error) {
// The file might be inaccessible due to wrong permissions
// or similar failures. We'll just count it as "corrupted".
console.error("Could not read session file ", ex, ex.stack);
corrupted = true;
} catch (ex if ex instanceof SyntaxError) {
console.error("Corrupt session file (invalid JSON found) ", ex, ex.stack);
// File is corrupted, try next file
corrupted = true;
} finally {

Просмотреть файл

@ -30,7 +30,6 @@ add_task(function* init() {
});
add_task(function* test_creation() {
let OLD_BACKUP = Path.join(Constants.Path.profileDir, "sessionstore.bak");
let OLD_UPGRADE_BACKUP = Path.join(Constants.Path.profileDir, "sessionstore.bak-0000000");
@ -115,6 +114,27 @@ add_task(function* test_recovery() {
yield File.writeAtomic(Paths.recoveryBackup, SOURCE);
yield File.writeAtomic(Paths.recovery, "<Invalid JSON>");
is((yield SessionFile.read()).source, SOURCE, "Recovered the correct source from the recovery file");
yield SessionFile.wipe();
});
add_task(function* test_recovery_inaccessible() {
// Can't do chmod() on non-UNIX platforms, we need that for this test.
if (AppConstants.platform != "macosx" && AppConstants.platform != "linux") {
return;
}
info("Making recovery file inaccessible, attempting to recover from recovery backup");
let SOURCE_RECOVERY = yield promiseSource("Paths.recovery");
let SOURCE = yield promiseSource("Paths.recoveryBackup");
yield File.makeDir(Paths.backups);
yield File.writeAtomic(Paths.recoveryBackup, SOURCE);
// Write a valid recovery file but make it inaccessible.
yield File.writeAtomic(Paths.recovery, SOURCE_RECOVERY);
yield File.setPermissions(Paths.recovery, { unixMode: 0 });
is((yield SessionFile.read()).source, SOURCE, "Recovered the correct source from the recovery file");
yield File.setPermissions(Paths.recovery, { unixMode: 0644 });
});
add_task(function* test_clean() {

Просмотреть файл

@ -8,14 +8,14 @@ const TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for notificat
let test = asyncTest(function* () {
yield loadTab(TEST_URI);
let gotEvents = waitForEvents();
let hud = yield openConsole();
let consoleOpened = promise.defer();
let gotEvents = waitForEvents(consoleOpened.promise);
let hud = yield openConsole().then(() => consoleOpened.resolve());
yield gotEvents;
});
function waitForEvents() {
function waitForEvents(onConsoleOpened) {
let deferred = promise.defer();
function webConsoleCreated(aID)
@ -37,7 +37,7 @@ function waitForEvents() {
Services.obs.removeObserver(observer, "web-console-message-created");
ok(aID, "we have a console ID");
is(typeof aNodeID, "string", "message node id is a string");
executeSoon(closeConsole);
onConsoleOpened.then(closeConsole);
}
let observer = {

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -1,29 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluetoothhfpmanagerbase_h__
#define mozilla_dom_bluetooth_bluetoothhfpmanagerbase_h__
#include "BluetoothProfileManagerBase.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothHfpManagerBase : public BluetoothProfileManagerBase
{
public:
/**
* Returns true if Sco is connected.
*/
virtual bool IsScoConnected() = 0;
};
#define BT_DECL_HFP_MGR_BASE \
BT_DECL_PROFILE_MGR_BASE \
virtual bool IsScoConnected() override;
END_BLUETOOTH_NAMESPACE
#endif //#ifndef mozilla_dom_bluetooth_bluetoothhfpmanagerbase_h__

Просмотреть файл

@ -1,270 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "BluetoothHidManager.h"
#include "BluetoothCommon.h"
#include "BluetoothService.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<BluetoothHidManager> sBluetoothHidManager;
bool sInShutdown = false;
} // anonymous namespace
NS_IMETHODIMP
BluetoothHidManager::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(sBluetoothHidManager);
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
HandleShutdown();
return NS_OK;
}
MOZ_ASSERT(false, "BluetoothHidManager got unexpected topic!");
return NS_ERROR_UNEXPECTED;
}
BluetoothHidManager::BluetoothHidManager()
{
Reset();
}
void
BluetoothHidManager::Reset()
{
mConnected = false;
mController = nullptr;
}
bool
BluetoothHidManager::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;
}
BluetoothHidManager::~BluetoothHidManager()
{
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
BluetoothHidManager*
BluetoothHidManager::Get()
{
MOZ_ASSERT(NS_IsMainThread());
// If we already exist, exit early
if (sBluetoothHidManager) {
return sBluetoothHidManager;
}
// If we're in shutdown, don't create a new instance
NS_ENSURE_FALSE(sInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothHidManager* manager = new BluetoothHidManager();
NS_ENSURE_TRUE(manager->Init(), nullptr);
sBluetoothHidManager = manager;
return sBluetoothHidManager;
}
void
BluetoothHidManager::HandleShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
sInShutdown = true;
Disconnect(nullptr);
sBluetoothHidManager = nullptr;
}
void
BluetoothHidManager::Connect(const nsAString& aDeviceAddress,
BluetoothProfileController* aController)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
MOZ_ASSERT(aController && !mController);
BluetoothService* bs = BluetoothService::Get();
if (!bs || sInShutdown) {
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
return;
}
if (mConnected) {
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_CONNECTED));
return;
}
mDeviceAddress = aDeviceAddress;
mController = aController;
if (NS_FAILED(bs->SendInputMessage(aDeviceAddress,
NS_LITERAL_STRING("Connect")))) {
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
return;
}
}
void
BluetoothHidManager::Disconnect(BluetoothProfileController* aController)
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
if (aController) {
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
}
return;
}
if (!mConnected) {
if (aController) {
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_DISCONNECTED));
}
return;
}
MOZ_ASSERT(!mDeviceAddress.IsEmpty());
MOZ_ASSERT(!mController);
mController = aController;
if (NS_FAILED(bs->SendInputMessage(mDeviceAddress,
NS_LITERAL_STRING("Disconnect")))) {
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
return;
}
}
void
BluetoothHidManager::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
BluetoothHidManager::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);
}
bool
BluetoothHidManager::IsConnected()
{
return mConnected;
}
void
BluetoothHidManager::HandleInputPropertyChanged(const BluetoothSignal& aSignal)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSignal.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue);
const InfallibleTArray<BluetoothNamedValue>& arr =
aSignal.value().get_ArrayOfBluetoothNamedValue();
MOZ_ASSERT(arr.Length() == 1);
const nsString& name = arr[0].name();
const BluetoothValue& value = arr[0].value();
if (name.EqualsLiteral("Connected")) {
MOZ_ASSERT(value.type() == BluetoothValue::Tbool);
MOZ_ASSERT(mConnected != value.get_bool());
mConnected = value.get_bool();
NotifyStatusChanged();
if (mConnected) {
OnConnect(EmptyString());
} else {
OnDisconnect(EmptyString());
}
}
}
void
BluetoothHidManager::NotifyStatusChanged()
{
MOZ_ASSERT(NS_IsMainThread());
NS_NAMED_LITERAL_STRING(type, BLUETOOTH_HID_STATUS_CHANGED_ID);
InfallibleTArray<BluetoothNamedValue> parameters;
BT_APPEND_NAMED_VALUE(parameters, "connected", mConnected);
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
}
void
BluetoothHidManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
const nsAString& aServiceUuid,
int aChannel)
{
// Do nothing here as bluez acquires service channel and connects for us
}
void
BluetoothHidManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
{
// Do nothing here as bluez acquires service channel and connects for us
}
void
BluetoothHidManager::GetAddress(nsAString& aDeviceAddress)
{
aDeviceAddress = mDeviceAddress;
}
NS_IMPL_ISUPPORTS(BluetoothHidManager, nsIObserver)

Просмотреть файл

@ -1,47 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluetoothhidmanager_h__
#define mozilla_dom_bluetooth_bluetoothhidmanager_h__
#include "BluetoothCommon.h"
#include "BluetoothProfileController.h"
#include "BluetoothProfileManagerBase.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothHidManager : public BluetoothProfileManagerBase
{
public:
BT_DECL_PROFILE_MGR_BASE
virtual void GetName(nsACString& aName)
{
aName.AssignLiteral("HID");
}
static BluetoothHidManager* Get();
virtual ~BluetoothHidManager();
// HID-specific functions
void HandleInputPropertyChanged(const BluetoothSignal& aSignal);
private:
BluetoothHidManager();
bool Init();
void Cleanup();
void HandleShutdown();
void NotifyStatusChanged();
// data member
bool mConnected;
nsString mDeviceAddress;
nsRefPtr<BluetoothProfileController> mController;
};
END_BLUETOOTH_NAMESPACE
#endif //#ifndef mozilla_dom_bluetooth_bluetoothhidmanager_h__

Просмотреть файл

@ -1,110 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluetoothprofilemanagerbase_h__
#define mozilla_dom_bluetooth_bluetoothprofilemanagerbase_h__
/**
* Error Messages used in Bluetooth profiles
*
* These error messages would be sent to Gaia as an argument of onError event.
*/
#define ERR_ALREADY_CONNECTED "AlreadyConnectedError"
#define ERR_ALREADY_DISCONNECTED "AlreadyDisconnectedError"
#define ERR_CONNECTION_FAILED "ConnectionFailedError"
#define ERR_DISCONNECTION_FAILED "DisconnectionFailedError"
#define ERR_NO_AVAILABLE_RESOURCE "NoAvailableResourceError"
#define ERR_REACHED_CONNECTION_LIMIT "ReachedConnectionLimitError"
#define ERR_SERVICE_CHANNEL_NOT_FOUND "DeviceChannelRetrievalError"
#define ERR_UNKNOWN_PROFILE "UnknownProfileError"
#define ERR_OPERATION_TIMEOUT "OperationTimeout"
#include "BluetoothCommon.h"
#include "nsIObserver.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothProfileController;
class BluetoothProfileResultHandler
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothProfileResultHandler);
virtual ~BluetoothProfileResultHandler() { }
virtual void OnError(nsresult aResult) { }
virtual void Init() { }
virtual void Deinit() { }
};
class BluetoothProfileManagerBase : public nsIObserver
{
public:
virtual void OnGetServiceChannel(const nsAString& aDeviceAddress,
const nsAString& aServiceUuid,
int aChannel) = 0;
virtual void OnUpdateSdpRecords(const nsAString& aDeviceAddress) = 0;
/**
* Returns the address of the connected device.
*/
virtual void GetAddress(nsAString& aDeviceAddress) = 0;
/**
* Returns true if the profile is connected.
*/
virtual bool IsConnected() = 0;
/**
* Connect to a specific remote device. When it has been done, the
* callback "OnConnect" will be invoked.
*/
virtual void Connect(const nsAString& aDeviceAddress,
BluetoothProfileController* aController) = 0;
/**
* Close the socket and then invoke the callback "OnDisconnect".
*/
virtual void Disconnect(BluetoothProfileController* aController) = 0;
/**
* If it establishes/releases a connection successfully, the error string
* will be empty. Otherwise, the error string shows the failure reason.
*/
virtual void OnConnect(const nsAString& aErrorStr) = 0;
virtual void OnDisconnect(const nsAString& aErrorStr) = 0;
/**
* Clean up profile resources and set mController as null.
*/
virtual void Reset() = 0;
/**
* Returns string of profile name.
*/
virtual void GetName(nsACString& aName) = 0;
};
#define BT_DECL_PROFILE_MGR_BASE \
public: \
NS_DECL_ISUPPORTS \
NS_DECL_NSIOBSERVER \
virtual void OnGetServiceChannel(const nsAString& aDeviceAddress, \
const nsAString& aServiceUuid, \
int aChannel) override; \
virtual void OnUpdateSdpRecords(const nsAString& aDeviceAddress) override; \
virtual void GetAddress(nsAString& aDeviceAddress) override; \
virtual bool IsConnected() override; \
virtual void Connect(const nsAString& aDeviceAddress, \
BluetoothProfileController* aController) override; \
virtual void Disconnect(BluetoothProfileController* aController) override; \
virtual void OnConnect(const nsAString& aErrorStr) override; \
virtual void OnDisconnect(const nsAString& AErrorStr) override; \
virtual void Reset() override;
END_BLUETOOTH_NAMESPACE
#endif //#ifndef mozilla_dom_bluetooth_bluetoothprofilemanagerbase_h__

Просмотреть файл

@ -1,134 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluetoothrillistener_h__
#define mozilla_dom_bluetooth_bluetoothrillistener_h__
#include "BluetoothCommon.h"
#include "nsAutoPtr.h"
#include "nsIIccService.h"
#include "nsIMobileConnectionService.h"
#include "nsITelephonyCallInfo.h"
#include "nsITelephonyService.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothRilListener;
class IccListener : public nsIIccListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIICCLISTENER
IccListener() { }
virtual ~IccListener() { }
bool Listen(bool aStart);
void SetOwner(BluetoothRilListener *aOwner);
private:
BluetoothRilListener* mOwner;
};
class MobileConnectionListener : public nsIMobileConnectionListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMOBILECONNECTIONLISTENER
MobileConnectionListener(uint32_t aClientId)
: mClientId(aClientId) { }
virtual ~MobileConnectionListener() { }
bool Listen(bool aStart);
private:
uint32_t mClientId;
};
class TelephonyListener : public nsITelephonyListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSITELEPHONYLISTENER
TelephonyListener() { }
virtual ~TelephonyListener() { }
bool Listen(bool aStart);
private:
nsresult HandleCallInfo(nsITelephonyCallInfo* aInfo, bool aSend);
};
class BluetoothRilListener
{
public:
BluetoothRilListener();
~BluetoothRilListener();
/**
* Start/Stop listening.
*
* @param aStart [in] whether to start/stop listening
*/
bool Listen(bool aStart);
/**
* Be informed that certain client's service has changed.
*
* @param aClientId [in] the client id with service change
* @param aRegistered [in] whether changed service is registered
*/
void ServiceChanged(uint32_t aClientId, bool aRegistered);
/**
* Enumerate current calls.
*/
void EnumerateCalls();
/**
* The id of client that mobile connection and icc info listeners
* are listening to.
*
* mClientId equals to number of total clients (array length of
* mobile connection listeners) if there is no available client to listen.
*/
uint32_t mClientId;
private:
/**
* Start/Stop listening of mobile connection and icc info.
*
* @param aStart [in] whether to start/stop listening
*/
bool ListenMobileConnAndIccInfo(bool aStart);
/**
* Select available client to listen and assign mClientId.
*
* mClientId is assigned to number of total clients (array length of
* mobile connection listeners) if there is no available client to listen.
*/
void SelectClient();
/**
* Array of mobile connection listeners.
*
* The length equals to number of total clients.
*/
nsTArray<nsRefPtr<MobileConnectionListener> > mMobileConnListeners;
nsRefPtr<IccListener> mIccListener;
nsRefPtr<TelephonyListener> mTelephonyListener;
};
END_BLUETOOTH_NAMESPACE
#endif

Просмотреть файл

@ -1,48 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_BluetoothSocketObserver_h
#define mozilla_dom_bluetooth_BluetoothSocketObserver_h
#include "BluetoothCommon.h"
#include "mozilla/ipc/UnixSocket.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothSocket;
class BluetoothSocketObserver
{
public:
virtual void ReceiveSocketData(
BluetoothSocket* aSocket,
nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage) = 0;
/**
* A callback function which would be called when a socket connection
* is established successfully. To be more specific, this would be called
* when socket state changes from CONNECTING/LISTENING to CONNECTED.
*/
virtual void OnSocketConnectSuccess(BluetoothSocket* aSocket) = 0;
/**
* A callback function which would be called when BluetoothSocket::Connect()
* fails.
*/
virtual void OnSocketConnectError(BluetoothSocket* aSocket) = 0;
/**
* A callback function which would be called when a socket connection
* is dropped. To be more specific, this would be called when socket state
* changes from CONNECTED/LISTENING to DISCONNECTED.
*/
virtual void OnSocketDisconnect(BluetoothSocket* aSocket) = 0;
};
END_BLUETOOTH_NAMESPACE
#endif

Просмотреть файл

@ -1,138 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ObexBase.h"
BEGIN_BLUETOOTH_NAMESPACE
int
AppendHeaderName(uint8_t* aRetBuf, int aBufferSize, const char* aName,
int aLength)
{
int headerLength = aLength + 3;
aRetBuf[0] = ObexHeaderId::Name;
aRetBuf[1] = (headerLength & 0xFF00) >> 8;
aRetBuf[2] = headerLength & 0x00FF;
memcpy(&aRetBuf[3], aName, (aLength < aBufferSize - 3)? aLength
: aBufferSize - 3);
return headerLength;
}
int
AppendHeaderBody(uint8_t* aRetBuf, int aBufferSize, const uint8_t* aData,
int aLength)
{
int headerLength = aLength + 3;
aRetBuf[0] = ObexHeaderId::Body;
aRetBuf[1] = (headerLength & 0xFF00) >> 8;
aRetBuf[2] = headerLength & 0x00FF;
memcpy(&aRetBuf[3], aData, (aLength < aBufferSize - 3)? aLength
: aBufferSize - 3);
return headerLength;
}
int
AppendHeaderEndOfBody(uint8_t* aRetBuf)
{
aRetBuf[0] = ObexHeaderId::EndOfBody;
aRetBuf[1] = 0x00;
aRetBuf[2] = 0x03;
return 3;
}
int
AppendHeaderLength(uint8_t* aRetBuf, int aObjectLength)
{
aRetBuf[0] = ObexHeaderId::Length;
aRetBuf[1] = (aObjectLength & 0xFF000000) >> 24;
aRetBuf[2] = (aObjectLength & 0x00FF0000) >> 16;
aRetBuf[3] = (aObjectLength & 0x0000FF00) >> 8;
aRetBuf[4] = aObjectLength & 0x000000FF;
return 5;
}
int
AppendHeaderConnectionId(uint8_t* aRetBuf, int aConnectionId)
{
aRetBuf[0] = ObexHeaderId::ConnectionId;
aRetBuf[1] = (aConnectionId & 0xFF000000) >> 24;
aRetBuf[2] = (aConnectionId & 0x00FF0000) >> 16;
aRetBuf[3] = (aConnectionId & 0x0000FF00) >> 8;
aRetBuf[4] = aConnectionId & 0x000000FF;
return 5;
}
void
SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength)
{
aRetBuf[0] = aOpcode;
aRetBuf[1] = (aPacketLength & 0xFF00) >> 8;
aRetBuf[2] = aPacketLength & 0x00FF;
}
bool
ParseHeaders(const uint8_t* aHeaderStart,
int aTotalLength,
ObexHeaderSet* aRetHandlerSet)
{
const uint8_t* ptr = aHeaderStart;
while (ptr - aHeaderStart < aTotalLength) {
ObexHeaderId headerId = (ObexHeaderId)*ptr++;
uint16_t contentLength = 0;
uint8_t highByte, lowByte;
// Defined in 2.1 OBEX Headers, IrOBEX 1.2
switch (headerId >> 6)
{
case 0x00:
// Null-terminated Unicode text, length prefixed with 2-byte
// unsigned integer.
case 0x01:
// byte sequence, length prefixed with 2 byte unsigned integer.
highByte = *ptr++;
lowByte = *ptr++;
contentLength = (((uint16_t)highByte << 8) | lowByte) - 3;
break;
case 0x02:
// 1 byte quantity
contentLength = 1;
break;
case 0x03:
// 4 byte quantity
contentLength = 4;
break;
}
// Length check to prevent from memory pollusion.
if (ptr + contentLength > aHeaderStart + aTotalLength) {
// Severe error occurred. We can't even believe the received data, so
// clear all headers.
MOZ_ASSERT(false);
aRetHandlerSet->ClearHeaders();
return false;
}
aRetHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, ptr));
ptr += contentLength;
}
return true;
}
END_BLUETOOTH_NAMESPACE

Просмотреть файл

@ -1,272 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_obexbase_h__
#define mozilla_dom_bluetooth_obexbase_h__
#include "BluetoothCommon.h"
#include "nsAutoPtr.h"
#include "nsTArray.h"
BEGIN_BLUETOOTH_NAMESPACE
const char FINAL_BIT = 0x80;
/*
* Defined in section 2.1 "OBEX Headers", IrOBEX ver 1.2
*/
enum ObexHeaderId {
Count = 0xC0,
Name = 0x01,
Type = 0x42,
Length = 0xC3,
TimeISO8601 = 0x44,
Time4Byte = 0xC4,
Description = 0x05,
Target = 0x46,
HTTP = 0x47,
Body = 0x48,
EndOfBody = 0x49,
Who = 0x4A,
ConnectionId = 0xCB,
AppParameters = 0x4C,
AuthChallenge = 0x4D,
AuthResponse = 0x4E,
ObjectClass = 0x4F
};
/*
* Defined in section 3.3 "OBEX Operations and Opcode definitions",
* IrOBEX ver 1.2
*/
enum ObexRequestCode {
Connect = 0x80,
Disconnect = 0x81,
Put = 0x02,
PutFinal = 0x82,
Get = 0x03,
GetFinal = 0x83,
SetPath = 0x85,
Abort = 0xFF
};
/*
* Defined in section 3.2.1 "Response Code values", IrOBEX ver 1.2
*/
enum ObexResponseCode {
Continue = 0x90,
Success = 0xA0,
Created = 0xA1,
Accepted = 0xA2,
NonAuthoritativeInfo = 0xA3,
NoContent = 0xA4,
ResetContent = 0xA5,
PartialContent = 0xA6,
MultipleChoices = 0xB0,
MovedPermanently = 0xB1,
MovedTemporarily = 0xB2,
SeeOther = 0xB3,
NotModified = 0xB4,
UseProxy = 0xB5,
BadRequest = 0xC0,
Unauthorized = 0xC1,
PaymentRequired = 0xC2,
Forbidden = 0xC3,
NotFound = 0xC4,
MethodNotAllowed = 0xC5,
NotAcceptable = 0xC6,
ProxyAuthenticationRequired = 0xC7,
RequestTimeOut = 0xC8,
Conflict = 0xC9,
Gone = 0xCA,
LengthRequired = 0xCB,
PreconditionFailed = 0xCC,
RequestedEntityTooLarge = 0xCD,
RequestUrlTooLarge = 0xCE,
UnsupprotedMediaType = 0xCF,
InternalServerError = 0xD0,
NotImplemented = 0xD1,
BadGateway = 0xD2,
ServiceUnavailable = 0xD3,
GatewayTimeout = 0xD4,
HttpVersionNotSupported = 0xD5,
DatabaseFull = 0xE0,
DatabaseLocked = 0xE1,
};
class ObexHeader
{
public:
ObexHeader(ObexHeaderId aId, int aDataLength, const uint8_t* aData)
: mId(aId)
, mDataLength(aDataLength)
, mData(nullptr)
{
mData = new uint8_t[mDataLength];
memcpy(mData, aData, aDataLength);
}
~ObexHeader()
{
}
ObexHeaderId mId;
int mDataLength;
nsAutoArrayPtr<uint8_t> mData;
};
class ObexHeaderSet
{
public:
ObexHeaderSet(uint8_t aOpcode) : mOpcode(aOpcode)
{
}
~ObexHeaderSet()
{
}
void AddHeader(ObexHeader* aHeader)
{
mHeaders.AppendElement(aHeader);
}
void GetName(nsString& aRetName) const
{
aRetName.Truncate();
int length = mHeaders.Length();
for (int i = 0; i < length; ++i) {
if (mHeaders[i]->mId == ObexHeaderId::Name) {
/*
* According to section 2.2.2 [Name] of IrOBEX spec, we know that
* the Name header is "a null terminated Unicode text string describing
* the name of the object.", and that's the reason why we need to minus
* 1 to get the real length of the file name.
*/
int nameLength = mHeaders[i]->mDataLength / 2 - 1;
uint8_t* ptr = mHeaders[i]->mData.get();
for (int j = 0; j < nameLength; ++j) {
char16_t c = ((((uint32_t)ptr[j * 2]) << 8) | ptr[j * 2 + 1]);
aRetName += c;
}
break;
}
}
}
void GetContentType(nsString& aRetContentType) const
{
aRetContentType.Truncate();
int length = mHeaders.Length();
for (int i = 0; i < length; ++i) {
if (mHeaders[i]->mId == ObexHeaderId::Type) {
uint8_t* ptr = mHeaders[i]->mData.get();
aRetContentType.AssignASCII((const char*)ptr);
break;
}
}
}
// @return file length, 0 means file length is unknown.
void GetLength(uint32_t* aRetLength) const
{
int length = mHeaders.Length();
*aRetLength = 0;
for (int i = 0; i < length; ++i) {
if (mHeaders[i]->mId == ObexHeaderId::Length) {
uint8_t* ptr = mHeaders[i]->mData.get();
*aRetLength = ((uint32_t)ptr[0] << 24) |
((uint32_t)ptr[1] << 16) |
((uint32_t)ptr[2] << 8) |
((uint32_t)ptr[3]);
return;
}
}
}
void GetBodyLength(int* aRetBodyLength) const
{
int length = mHeaders.Length();
*aRetBodyLength = 0;
for (int i = 0; i < length; ++i) {
if (mHeaders[i]->mId == ObexHeaderId::Body ||
mHeaders[i]->mId == ObexHeaderId::EndOfBody) {
*aRetBodyLength = mHeaders[i]->mDataLength;
return;
}
}
}
void GetBody(uint8_t** aRetBody) const
{
int length = mHeaders.Length();
*aRetBody = nullptr;
for (int i = 0; i < length; ++i) {
if (mHeaders[i]->mId == ObexHeaderId::Body ||
mHeaders[i]->mId == ObexHeaderId::EndOfBody) {
uint8_t* ptr = mHeaders[i]->mData.get();
*aRetBody = new uint8_t[mHeaders[i]->mDataLength];
memcpy(*aRetBody, ptr, mHeaders[i]->mDataLength);
return;
}
}
}
bool Has(ObexHeaderId aId) const
{
int length = mHeaders.Length();
for (int i = 0; i < length; ++i) {
if (mHeaders[i]->mId == aId) {
return true;
}
}
return false;
}
void ClearHeaders()
{
mHeaders.Clear();
}
private:
uint8_t mOpcode;
nsTArray<nsAutoPtr<ObexHeader> > mHeaders;
};
int AppendHeaderName(uint8_t* aRetBuf, int aBufferSize, const char* aName,
int aLength);
int AppendHeaderBody(uint8_t* aRetBuf, int aBufferSize, const uint8_t* aData,
int aLength);
int AppendHeaderEndOfBody(uint8_t* aRetBuf);
int AppendHeaderLength(uint8_t* aRetBuf, int aObjectLength);
int AppendHeaderConnectionId(uint8_t* aRetBuf, int aConnectionId);
void SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength);
/**
* @return true when the message was parsed without any error, false otherwise.
*/
bool ParseHeaders(const uint8_t* aHeaderStart,
int aTotalLength,
ObexHeaderSet* aRetHanderSet);
END_BLUETOOTH_NAMESPACE
#endif

Просмотреть файл

@ -11,12 +11,19 @@ if CONFIG['MOZ_B2G_BT']:
#
SOURCES += [
'BluetoothHidManager.cpp',
'BluetoothInterface.cpp',
'BluetoothInterfaceHelpers.cpp',
'BluetoothUtils.cpp',
'BluetoothUuid.cpp'
'BluetoothUuid.cpp',
'ObexBase.cpp'
]
if CONFIG['MOZ_B2G_RIL']:
SOURCES += [
'BluetoothRilListener.cpp'
]
if CONFIG['MOZ_B2G_BT_API_V2']:
SOURCES += [
'bluetooth2/BluetoothAdapter.cpp',
@ -27,7 +34,6 @@ if CONFIG['MOZ_B2G_BT']:
'bluetooth2/BluetoothGattCharacteristic.cpp',
'bluetooth2/BluetoothGattDescriptor.cpp',
'bluetooth2/BluetoothGattService.cpp',
'bluetooth2/BluetoothHidManager.cpp',
'bluetooth2/BluetoothManager.cpp',
'bluetooth2/BluetoothPairingHandle.cpp',
'bluetooth2/BluetoothPairingListener.cpp',
@ -37,12 +43,7 @@ if CONFIG['MOZ_B2G_BT']:
'bluetooth2/ipc/BluetoothChild.cpp',
'bluetooth2/ipc/BluetoothParent.cpp',
'bluetooth2/ipc/BluetoothServiceChildProcess.cpp',
'bluetooth2/ObexBase.cpp'
]
if CONFIG['MOZ_B2G_RIL']:
SOURCES += [
'bluetooth2/BluetoothRilListener.cpp',
]
LOCAL_INCLUDES += [
'bluetooth2',
'bluetooth2/ipc',
@ -52,7 +53,6 @@ if CONFIG['MOZ_B2G_BT']:
SOURCES += [
'bluetooth1/BluetoothAdapter.cpp',
'bluetooth1/BluetoothDevice.cpp',
'bluetooth1/BluetoothHidManager.cpp',
'bluetooth1/BluetoothManager.cpp',
'bluetooth1/BluetoothProfileController.cpp',
'bluetooth1/BluetoothPropertyContainer.cpp',
@ -61,12 +61,7 @@ if CONFIG['MOZ_B2G_BT']:
'bluetooth1/ipc/BluetoothChild.cpp',
'bluetooth1/ipc/BluetoothParent.cpp',
'bluetooth1/ipc/BluetoothServiceChildProcess.cpp',
'bluetooth1/ObexBase.cpp'
]
if CONFIG['MOZ_B2G_RIL']:
SOURCES += [
'bluetooth1/BluetoothRilListener.cpp',
]
LOCAL_INCLUDES += [
'bluetooth1',
'bluetooth1/ipc',

Просмотреть файл

@ -17,6 +17,7 @@
#include "nsDOMTokenList.h"
#include "nsFocusManager.h"
#include "nsFrame.h"
#include "nsGenericHTMLElement.h"
#include "nsIDocument.h"
#include "nsIDocShell.h"
#include "nsIDOMDocument.h"
@ -622,10 +623,16 @@ SelectionCarets::SelectWord()
}
} else {
nsIContent* focusedContent = GetFocusedContent();
if (focusedContent && focusedContent->GetTextEditorRootContent()) {
nsIDOMWindow* win = mPresShell->GetDocument()->GetWindow();
if (win) {
fm->ClearFocus(win);
if (focusedContent) {
// Clear focus if content was editable element, or contentEditable.
nsGenericHTMLElement* focusedGeneric =
nsGenericHTMLElement::FromContent(focusedContent);
if (focusedContent->GetTextEditorRootContent() ||
(focusedGeneric && focusedGeneric->IsContentEditable())) {
nsIDOMWindow* win = mPresShell->GetDocument()->GetWindow();
if (win) {
fm->ClearFocus(win);
}
}
}
}

Просмотреть файл

@ -142,20 +142,23 @@ LogManager.prototype = {
this._prefs = null;
},
get _logFileDirectory() {
// At this point we don't allow a custom directory for the logs so
// about:sync-log can be used. We could fix this later if necessary.
return FileUtils.getDir("ProfD", ["weave", "logs"]);
get _logFileSubDirectoryEntries() {
// At this point we don't allow a custom directory for the logs, nor allow
// it to be outside the profile directory.
// This returns an array of the the relative directory entries below the
// profile dir, and is the directory about:sync-log uses.
return ["weave", "logs"];
},
/**
* Copy an input stream to the named file, doing everything off the main
* thread.
* outputFile is an nsIFile, but is used only for the name.
* Returns a promise that is resolved with the file modification date on
* completion or rejected if there is an error.
* outputFileName is a string with the tail of the filename - the file will
* be created in the log directory.
* Returns a promise that is resolved<undefined> on completion or rejected if
* there is an error.
*/
_copyStreamToFile: Task.async(function* (inputStream, outputFile) {
_copyStreamToFile: Task.async(function* (inputStream, outputFileName) {
// The log data could be large, so we don't want to pass it all in a single
// message, so use BUFFER_SIZE chunks.
const BUFFER_SIZE = 8192;
@ -163,7 +166,11 @@ LogManager.prototype = {
// get a binary stream
let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
binaryStream.setInputStream(inputStream);
yield OS.File.makeDir(outputFile.parent.path, { ignoreExisting: true });
// We assume the profile directory exists, but not that the dirs under it do.
let profd = FileUtils.getDir("ProfD", []);
let outputFile = FileUtils.getDir("ProfD", this._logFileSubDirectoryEntries);
yield OS.File.makeDir(outputFile.path, { ignoreExisting: true, from: profd.path });
outputFile.append(outputFileName);
let output = yield OS.File.open(outputFile.path, { write: true} );
try {
while (true) {
@ -221,12 +228,10 @@ LogManager.prototype = {
// We have reasonPrefix at the start of the filename so all "error"
// logs are grouped in about:sync-log.
let filename = reasonPrefix + "-" + this.logFilePrefix + "-" + Date.now() + ".txt";
let file = this._logFileDirectory;
file.append(filename);
this._log.trace("Beginning stream copy to " + file.leafName + ": " +
this._log.trace("Beginning stream copy to " + filename + ": " +
Date.now());
try {
yield this._copyStreamToFile(inStream, file);
yield this._copyStreamToFile(inStream, filename);
this._log.trace("onCopyComplete", Date.now());
} catch (ex) {
this._log.error("Failed to copy log stream to file", ex);
@ -256,7 +261,8 @@ LogManager.prototype = {
*/
cleanupLogs: Task.async(function* () {
this._cleaningUpFileLogs = true;
let iterator = new OS.File.DirectoryIterator(this._logFileDirectory.path);
let logDir = FileUtils.getDir("ProfD", this._logFileSubDirectoryEntries);
let iterator = new OS.File.DirectoryIterator(logDir.path);
let maxAge = this._prefs.get("log.appender.file.maxErrorAge", DEFAULT_MAX_ERROR_AGE);
let threshold = Date.now() - 1000 * maxAge;

Просмотреть файл

@ -6,6 +6,7 @@
Cu.import("resource://services-common/logmanager.js");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
function run_test() {
run_next_test();
@ -101,3 +102,34 @@ add_task(function* test_SharedLogs() {
lm1.finalize();
lm2.finalize();
});
// A little helper to test what log files exist. We expect exactly zero (if
// prefix is null) or exactly one with the specified prefix.
function checkLogFile(prefix) {
let logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
let entries = logsdir.directoryEntries;
if (!prefix) {
// expecting no files.
ok(!entries.hasMoreElements());
} else {
// expecting 1 file.
ok(entries.hasMoreElements());
let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
equal(logfile.leafName.slice(-4), ".txt");
ok(logfile.leafName.startsWith(prefix + "-test-"), logfile.leafName);
// and remove it ready for the next check.
logfile.remove(false);
}
}
// Test that we correctly write error logs by default
add_task(function* test_logFileErrorDefault() {
let lm = new LogManager("log-manager.test.", ["TestLog2"], "test");
let log = Log.repository.getLogger("TestLog2");
log.error("an error message");
yield lm.resetFileLog(lm.REASON_ERROR);
// One error log file exists.
checkLogFile("error");
lm.finalize();
});

Просмотреть файл

@ -652,16 +652,18 @@ function EnvironmentCache() {
this._updateSettings();
#ifndef MOZ_WIDGET_ANDROID
this._currentEnvironment.profile = {};
#endif
// Build the remaining asynchronous parts of the environment. Don't register change listeners
// until the initial environment has been built.
this._addonBuilder = new EnvironmentAddonBuilder(this);
this._initTask = Promise.all([this._addonBuilder.init(), this._updateProfile()])
let p = [ this._addonBuilder.init() ];
#ifndef MOZ_WIDGET_ANDROID
this._currentEnvironment.profile = {};
p.push(this._updateProfile());
#endif
this._initTask = Promise.all(p)
.then(
() => {
this._initTask = null;
@ -671,7 +673,7 @@ function EnvironmentCache() {
},
(err) => {
// log errors but eat them for consumers
this._log.error("error while initializing", err);
this._log.error("EnvironmentCache - error while initializing", err);
this._initTask = null;
this._startWatchingPrefs();
this._addonBuilder.watchForChanges();
@ -1019,7 +1021,9 @@ EnvironmentCache.prototype = {
let gfxData = {
D2DEnabled: getGfxField("D2DEnabled", null),
DWriteEnabled: getGfxField("DWriteEnabled", null),
DWriteVersion: getGfxField("DWriteVersion", null),
// The following line is disabled due to main thread jank and will be enabled
// again as part of bug 1154500.
//DWriteVersion: getGfxField("DWriteVersion", null),
adapters: [],
};

Просмотреть файл

@ -604,13 +604,16 @@ let Impl = {
", aOptions " + JSON.stringify(aOptions));
let pingData = this.assemblePing(aType, aPayload, aOptions);
let archivePromise = this._archivePing(pingData)
.catch(e => this._log.error("addPendingPing - Failed to archive ping " + pingData.id, e));
let savePromise = TelemetryFile.savePing(pingData, aOptions.overwrite);
let archivePromise = this._archivePing(pingData).catch(e => {
this._log.error("addPendingPing - Failed to archive ping " + pingData.id, e);
});
// Wait for both the archiving and ping persistence to complete.
let promises = [
savePromise,
archivePromise,
TelemetryFile.savePing(pingData, aOptions.overwrite),
];
return Promise.all(promises).then(() => pingData.id);
},
@ -1076,7 +1079,8 @@ let Impl = {
const creationDate = new Date(aPingData.creationDate);
const filePath = getArchivedPingPath(aPingData.id, creationDate, aPingData.type);
yield OS.File.makeDir(OS.Path.dirname(filePath), { ignoreExisting: true });
yield OS.File.makeDir(OS.Path.dirname(filePath), { ignoreExisting: true,
from: OS.Constants.Path.profileDir });
yield TelemetryFile.savePingToFile(aPingData, filePath, true);
}),

Просмотреть файл

@ -249,7 +249,8 @@ function toLocalTimeISOString(date) {
}
let sign = (n) => n >= 0 ? "+" : "-";
let tzOffset = date.getTimezoneOffset();
// getTimezoneOffset counter-intuitively returns -60 for UTC+1.
let tzOffset = - date.getTimezoneOffset();
// YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
return padNumber(date.getFullYear(), 4)
@ -259,8 +260,8 @@ function toLocalTimeISOString(date) {
+ ":" + padNumber(date.getMinutes(), 2)
+ ":" + padNumber(date.getSeconds(), 2)
+ "." + date.getMilliseconds()
+ sign(tzOffset) + Math.abs(Math.floor(tzOffset / 60))
+ ":" + Math.abs(tzOffset % 60);
+ sign(tzOffset) + padNumber(Math.floor(Math.abs(tzOffset / 60)), 2)
+ ":" + padNumber(Math.abs(tzOffset % 60), 2);
}
/**
@ -1703,9 +1704,8 @@ let Impl = {
addClientId: true,
addEnvironment: true,
overwrite: true,
filePath: file.path,
};
return TelemetryPing.addPendingPing(getPingType(payload), payload, options);
return TelemetryPing.savePing(getPingType(payload), payload, file.path, options);
},
/**
@ -2071,7 +2071,7 @@ let Impl = {
if (abortedExists) {
this._log.trace("_checkAbortedSessionPing - aborted session found: " + FILE_PATH);
yield this._abortedSessionSerializer.enqueueTask(
() => TelemetryPing.addPendingPing(FILE_PATH, true));
() => TelemetryPing.addPendingPingFromFile(FILE_PATH, true));
}
}),

Просмотреть файл

@ -112,7 +112,7 @@ Structure::
gfx: {
D2DEnabled: <bool>, // null on failure
DWriteEnabled: <bool>, // null on failure
DWriteVersion: <string>, // null on failure
//DWriteVersion: <string>, // temporarily removed, pending bug 1154500
adapters: [
{
description: <string>, // e.g. "Intel(R) HD Graphics 4600", null on failure

Просмотреть файл

@ -392,11 +392,14 @@ function checkSystemSection(data) {
let gfxData = data.system.gfx;
Assert.ok("D2DEnabled" in gfxData);
Assert.ok("DWriteEnabled" in gfxData);
Assert.ok("DWriteVersion" in gfxData);
// DWriteVersion is disabled due to main thread jank and will be enabled
// again as part of bug 1154500.
//Assert.ok("DWriteVersion" in gfxData);
if (gIsWindows) {
Assert.equal(typeof gfxData.D2DEnabled, "boolean");
Assert.equal(typeof gfxData.DWriteEnabled, "boolean");
Assert.ok(checkString(gfxData.DWriteVersion));
// As above, will be enabled again as part of bug 1154500.
//Assert.ok(checkString(gfxData.DWriteVersion));
}
Assert.ok("adapters" in gfxData);

Просмотреть файл

@ -212,15 +212,23 @@ function checkPayloadInfo(data) {
const ALLOWED_REASONS = [
"environment-change", "shutdown", "daily", "saved-session", "test-ping"
];
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
let numberCheck = arg => { return (typeof arg == "number"); };
let positiveNumberCheck = arg => { return numberCheck(arg) && (arg >= 0); };
let stringCheck = arg => { return (typeof arg == "string") && (arg != ""); };
let isoDateCheck = arg => { return stringCheck(arg) && !Number.isNaN(Date.parse(arg)); }
let revisionCheck = arg => {
return (Services.appinfo.isOfficial) ? stringCheck(arg) : (typeof arg == "string");
};
let uuidCheck = arg => uuidRegex.test(arg);
let uuidCheck = arg => {
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
return uuidRegex.test(arg);
};
let isoDateCheck = arg => {
// We expect use of this version of the ISO format:
// 2015-04-12T18:51:19.1+00:00
const isoDateRegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+[+-]\d{2}:\d{2}$/;
return stringCheck(arg) && !Number.isNaN(Date.parse(arg)) &&
isoDateRegEx.test(arg);
};
const EXPECTED_INFO_FIELDS_TYPES = {
reason: stringCheck,
@ -1582,6 +1590,7 @@ add_task(function* test_schedulerUserIdle() {
// We should not miss midnight when going to idle.
now.setHours(23);
now.setMinutes(50);
fakeNow(now);
fakeIdleNotification("idle");
Assert.equal(schedulerTimeout, 10 * 60 * 1000);

Просмотреть файл

@ -65,11 +65,20 @@ let WebProgressListener = {
_setupJSON: function setupJSON(aWebProgress, aRequest) {
if (aWebProgress) {
let domWindowID;
try {
domWindowID = aWebProgress && aWebProgress.DOMWindowID;
} catch (e) {
// If nsDocShell::Destroy has already been called, then we'll
// get NS_NOINTERFACE when trying to get the DOM window ID.
domWindowID = null;
}
aWebProgress = {
isTopLevel: aWebProgress.isTopLevel,
isLoadingDocument: aWebProgress.isLoadingDocument,
loadType: aWebProgress.loadType,
DOMWindowID: aWebProgress.DOMWindowID,
DOMWindowID: domWindowID
};
}

Просмотреть файл

@ -99,67 +99,11 @@ this.ForgetAboutSite = {
}
// Downloads
let useJSTransfer = false;
try {
// This method throws an exception if the old Download Manager is disabled.
Services.downloads.activeDownloadCount;
} catch (ex) {
useJSTransfer = true;
}
if (useJSTransfer) {
Task.spawn(function*() {
let list = yield Downloads.getList(Downloads.ALL);
list.removeFinished(download => hasRootDomain(
NetUtil.newURI(download.source.url).host, aDomain));
}).then(null, Cu.reportError);
}
else {
let dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager);
// Active downloads
for (let enumerator of [dm.activeDownloads, dm.activePrivateDownloads]) {
while (enumerator.hasMoreElements()) {
let dl = enumerator.getNext().QueryInterface(Ci.nsIDownload);
if (hasRootDomain(dl.source.host, aDomain)) {
dl.cancel();
dl.remove();
}
}
const deleteAllLike = function(db) {
// NOTE: This is lossy, but we feel that it is OK to be lossy here and not
// invoke the cost of creating a URI for each download entry and
// ensure that the hostname matches.
let stmt = db.createStatement(
"DELETE FROM moz_downloads " +
"WHERE source LIKE ?1 ESCAPE '/' " +
"AND state NOT IN (?2, ?3, ?4)"
);
let pattern = stmt.escapeStringForLIKE(aDomain, "/");
stmt.bindByIndex(0, "%" + pattern + "%");
stmt.bindByIndex(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
stmt.bindByIndex(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
stmt.bindByIndex(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
try {
stmt.execute();
}
finally {
stmt.finalize();
}
}
// Completed downloads
deleteAllLike(dm.DBConnection);
deleteAllLike(dm.privateDBConnection);
// We want to rebuild the list if the UI is showing, so dispatch the
// observer topic
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.notifyObservers(null, "download-manager-remove-download", null);
}
}
Task.spawn(function*() {
let list = yield Downloads.getList(Downloads.ALL);
list.removeFinished(download => hasRootDomain(
NetUtil.newURI(download.source.url).host, aDomain));
}).then(null, Cu.reportError);
// Passwords
let lm = Cc["@mozilla.org/login-manager;1"].

Просмотреть файл

@ -15,7 +15,6 @@ var profileDir = do_get_profile();
function cleanUp()
{
let files = [
"downloads.sqlite",
"places.sqlite",
"cookies.sqlite",
"signons.sqlite",
@ -30,14 +29,3 @@ function cleanUp()
}
}
cleanUp();
function oldDownloadManagerDisabled()
{
try {
// This method throws an exception if the old Download Manager is disabled.
Services.downloads.activeDownloadCount;
} catch (ex) {
return true;
}
return false;
}

Просмотреть файл

@ -107,74 +107,6 @@ function check_cookie_exists(aDomain, aExists)
checker(cm.cookieExists(cookie));
}
/**
* Adds a download to download history.
*
* @param aURIString
* The string of the URI to add.
* @param aIsActive
* If it should be set to an active state in the database. This does not
* make it show up in the list of active downloads however!
*/
function add_download(aURIString, aIsActive)
{
function makeGUID() {
let guid = "";
for (var i = 0; i < 12; i++)
guid += Math.floor(Math.random() * 10);
return guid;
}
check_downloaded(aURIString, false);
let db = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager).
DBConnection;
let stmt = db.createStatement(
"INSERT INTO moz_downloads (source, state, guid) " +
"VALUES (:source, :state, :guid)"
);
stmt.params.source = aURIString;
stmt.params.state = aIsActive ? Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING :
Ci.nsIDownloadManager.DOWNLOAD_FINISHED;
stmt.params.guid = makeGUID();
try {
stmt.execute();
}
finally {
stmt.finalize();
}
check_downloaded(aURIString, true);
}
/**
* Checks to ensure a URI string is in download history or not.
*
* @param aURIString
* The string of the URI to check.
* @param aIsDownloaded
* True if the URI should be downloaded, false otherwise.
*/
function check_downloaded(aURIString, aIsDownloaded)
{
let db = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager).
DBConnection;
let stmt = db.createStatement(
"SELECT * " +
"FROM moz_downloads " +
"WHERE source = :source"
);
stmt.params.source = aURIString;
let checker = aIsDownloaded ? do_check_true : do_check_false;
try {
checker(stmt.executeStep());
}
finally {
stmt.finalize();
}
}
/**
* Adds a disabled host to the login manager.
*
@ -380,51 +312,6 @@ function test_cookie_not_cleared_with_uri_contains_domain()
check_cookie_exists(TEST_DOMAIN, true);
}
// Download Manager
function test_download_history_cleared_with_direct_match()
{
if (oldDownloadManagerDisabled()) {
return;
}
const TEST_URI = "http://mozilla.org/foo";
add_download(TEST_URI, false);
ForgetAboutSite.removeDataFromDomain("mozilla.org");
check_downloaded(TEST_URI, false);
}
function test_download_history_cleared_with_subdomain()
{
if (oldDownloadManagerDisabled()) {
return;
}
const TEST_URI = "http://www.mozilla.org/foo";
add_download(TEST_URI, false);
ForgetAboutSite.removeDataFromDomain("mozilla.org");
check_downloaded(TEST_URI, false);
}
function test_download_history_not_cleared_with_active_direct_match()
{
if (oldDownloadManagerDisabled()) {
return;
}
// Tests that downloads marked as active in the db are not deleted from the db
const TEST_URI = "http://mozilla.org/foo";
add_download(TEST_URI, true);
ForgetAboutSite.removeDataFromDomain("mozilla.org");
check_downloaded(TEST_URI, true);
// Reset state
let db = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager).
DBConnection;
db.executeSimpleSQL("DELETE FROM moz_downloads");
check_downloaded(TEST_URI, false);
}
// Login Manager
function test_login_manager_disabled_hosts_cleared_with_direct_match()
{
@ -650,12 +537,6 @@ let tests = [
test_cookie_cleared_with_subdomain,
test_cookie_not_cleared_with_uri_contains_domain,
// Download Manager
// Note: active downloads tested in test_removeDataFromDomain_activeDownloads.js
test_download_history_cleared_with_direct_match,
test_download_history_cleared_with_subdomain,
test_download_history_not_cleared_with_active_direct_match,
// Login Manager
test_login_manager_disabled_hosts_cleared_with_direct_match,
test_login_manager_disabled_hosts_cleared_with_subdomain,

Просмотреть файл

@ -807,6 +807,8 @@ function LazyMapProxyHandler () {
}
return target.delete(key);
};
case "has":
return key => target.has(key);
default:
return target[name];
}

Просмотреть файл

@ -35,7 +35,13 @@ function checkMainPropertyList(aPropertyListRoot) {
const PRIMITIVE = PropertyListUtils.TYPE_PRIMITIVE;
checkValue(aPropertyListRoot, PropertyListUtils.TYPE_DICTIONARY);
// Check .has()
Assert.ok(aPropertyListRoot.has("Boolean"));
Assert.ok(!aPropertyListRoot.has("Nonexistent"));
checkValue(aPropertyListRoot.get("Boolean"), PRIMITIVE, false);
let array = aPropertyListRoot.get("Array");
checkValue(array, PropertyListUtils.TYPE_ARRAY);
do_check_eq(array.length, 8);

Просмотреть файл

@ -387,7 +387,7 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir,
return false;
CopyFileIntoUpdateDir(appDir, kUpdaterINI, updateDir);
#endif
#if defined(XP_UNIX) && !defined(XP_MACOSX)
#if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(ANDROID)
nsCOMPtr<nsIFile> iconDir;
appDir->Clone(getter_AddRefs(iconDir));
iconDir->AppendNative(NS_LITERAL_CSTRING("icons"));