Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2013-09-14 20:31:22 -04:00
commit e8180505f0
112 changed files with 3375 additions and 1698 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1378508419000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1379114379000">
<emItems>
<emItem blockID="i350" id="sqlmoz@facebook.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
@ -19,6 +19,10 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i404" id="{a9bb9fa0-4122-4c75-bd9a-bc27db3f9155}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i8" id="{B13721C7-F507-4982-B2E5-502A71474FED}">
<versionRange minVersion=" " severity="1">
</versionRange>
@ -216,8 +220,8 @@
<versionRange minVersion="0.1" maxVersion="14.4.0" severity="1">
</versionRange>
</emItem>
<emItem blockID="i93" id="{68b8676b-99a5-46d1-b390-22411d8bcd61}">
<versionRange minVersion="0" maxVersion="*">
<emItem blockID="i449" id="gystqfr@ylgga.com">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i142" id="{a3a5c777-f583-4fef-9380-ab4add1bc2a8}">
@ -425,7 +429,7 @@
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i404" id="{a9bb9fa0-4122-4c75-bd9a-bc27db3f9155}">
<emItem blockID="i448" id="{0134af61-7a0c-4649-aeca-90d776060cb3}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
@ -602,6 +606,10 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i93" id="{68b8676b-99a5-46d1-b390-22411d8bcd61}">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i439" id="{d2cf9842-af95-48cd-b873-bfbb48cd7f5e}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>

View File

@ -1072,7 +1072,7 @@ pref("devtools.commands.dir", "");
// Disable the app manager
pref("devtools.appmanager.enabled", true);
pref("devtools.appmanager.simulatorInstallPage", "https://addons.mozilla.org/firefox/addon/firefox-os-simulator/");
pref("devtools.appmanager.firstrun", true);
// Toolbox preferences
pref("devtools.toolbox.footer.height", 250);

View File

@ -159,10 +159,11 @@ SocialUI = {
}
break;
case "social:profile-changed":
// make sure anything that happens here only affects the provider for
// which the profile is changing, and that anything we call actually
// needs to change based on profile data.
if (this._matchesCurrentProvider(data)) {
SocialToolbar.updateProvider();
SocialMarks.update();
SocialChatBar.update();
}
break;
case "social:frameworker-error":
@ -215,13 +216,20 @@ SocialUI = {
// enabled == true means we at least have a defaultProvider
let provider = Social.provider || Social.defaultProvider;
// We only need to update the command itself - all our menu items use it.
let label = gNavigatorBundle.getFormattedString(Social.provider ?
"social.turnOff.label" :
"social.turnOn.label",
[provider.name]);
let accesskey = gNavigatorBundle.getString(Social.provider ?
"social.turnOff.accesskey" :
"social.turnOn.accesskey");
let label;
if (Social.providers.length == 1) {
label = gNavigatorBundle.getFormattedString(Social.provider
? "social.turnOff.label"
: "social.turnOn.label",
[provider.name]);
} else {
label = gNavigatorBundle.getString(Social.provider
? "social.turnOffAll.label"
: "social.turnOnAll.label");
}
let accesskey = gNavigatorBundle.getString(Social.provider
? "social.turnOff.accesskey"
: "social.turnOn.accesskey");
toggleCommand.setAttribute("label", label);
toggleCommand.setAttribute("accesskey", accesskey);
}
@ -868,17 +876,19 @@ SocialToolbar = {
toggleNotificationsCommand.setAttribute("hidden", !socialEnabled);
let parent = document.getElementById("social-notification-panel");
while (parent.hasChildNodes()) {
let frame = parent.firstChild;
SharedFrame.forgetGroup(frame.id);
parent.removeChild(frame);
}
let tbi = document.getElementById("social-provider-button");
if (tbi) {
// buttons after social-provider-button are ambient icons
// buttons after social-provider-button are ambient icons, remove the
// button and the attached shared frame.
while (tbi.nextSibling) {
tbi.parentNode.removeChild(tbi.nextSibling);
let tb = tbi.nextSibling;
let nid = tb.getAttribute("notificationFrameId");
let frame = document.getElementById(nid);
if (frame) {
SharedFrame.forgetGroup(frame.id);
parent.removeChild(frame);
}
tbi.parentNode.removeChild(tb);
}
}
},

View File

@ -1119,18 +1119,25 @@ var gBrowserInit = {
// If the user manually opens the download manager before the timeout, the
// downloads will start right away, and getting the service again won't hurt.
setTimeout(function() {
let DownloadsCommon =
Cu.import("resource:///modules/DownloadsCommon.jsm", {}).DownloadsCommon;
if (DownloadsCommon.useJSTransfer) {
// Open the data link without initalizing nsIDownloadManager.
DownloadsCommon.initializeAllDataLinks();
} else {
// Initalizing nsIDownloadManager will trigger the data link.
Services.downloads;
try {
let DownloadsCommon =
Cu.import("resource:///modules/DownloadsCommon.jsm", {}).DownloadsCommon;
if (DownloadsCommon.useJSTransfer) {
// Open the data link without initalizing nsIDownloadManager.
DownloadsCommon.initializeAllDataLinks();
let DownloadsTaskbar =
Cu.import("resource:///modules/DownloadsTaskbar.jsm", {}).DownloadsTaskbar;
DownloadsTaskbar.registerIndicator(window);
} else {
// Initalizing nsIDownloadManager will trigger the data link.
Services.downloads;
let DownloadTaskbarProgress =
Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
DownloadTaskbarProgress.onBrowserWindowLoad(window);
}
} catch (ex) {
Cu.reportError(ex);
}
let DownloadTaskbarProgress =
Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
DownloadTaskbarProgress.onBrowserWindowLoad(window);
}, 10000);
// The object handling the downloads indicator is also initialized here in the

View File

@ -7,6 +7,7 @@ function test() {
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
runSocialTestWithProvider(gProviders, function (finishcb) {
Social.enabled = true;
runSocialTests(tests, undefined, undefined, function() {
Services.prefs.clearUserPref("social.allowMultipleWorkers");
finishcb();

View File

@ -2,18 +2,36 @@
* 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/. */
let manifest = { // normal provider
name: "provider 1",
let manifests = [{ // normal provider
name: "provider example.com",
origin: "https://example.com",
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
};
}, { // used for testing install
name: "provider test1",
origin: "https://test1.example.com",
statusURL: "https://test1.example.com/browser/browser/base/content/test/social/social_panel.html",
iconURL: "https://test1.example.com/browser/browser/base/content/test/moz.png",
}];
function test() {
waitForExplicitFinish();
runSocialTestWithProvider(manifest, function (finishcb) {
runSocialTests(tests, undefined, undefined, finishcb);
// required to test status button in combination with the toolbaritem
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
// Preset the currentSet so the statusbutton is in the toolbar on addition. We
// bypass the SocialStatus class here since it requires the manifest already
// be installed.
let tbh = SocialStatus._toolbarHelper;
tbh.setPersistentPosition(tbh.idFromOrgin(manifests[1].origin));
runSocialTestWithProvider(manifests, function (finishcb) {
runSocialTests(tests, undefined, undefined, function() {
Services.prefs.clearUserPref("social.allowMultipleWorkers");
SocialStatus.removePosition(manifests[1].origin);
finishcb();
});
});
}
@ -37,7 +55,7 @@ var tests = {
},
testProfileSet: function(next) {
let statusIcon = document.getElementById("social-provider-button").style.listStyleImage;
is(statusIcon, "url(\"" + manifest.iconURL + "\")", "manifest iconURL is showing");
is(statusIcon, "url(\"" + manifests[0].iconURL + "\")", "manifest iconURL is showing");
let profile = {
portrait: "https://example.com/portrait.jpg",
userName: "trickster",
@ -167,14 +185,32 @@ var tests = {
}, "statusIcon was never found");
},
testProfileUnset: function(next) {
Social.provider.updateUserProfile({});
// check dom values
let ambientIcons = document.querySelectorAll("#social-toolbar-item > box");
for (let ambientIcon of ambientIcons) {
ok(ambientIcon.collapsed, "ambient icon (" + ambientIcon.id + ") is collapsed");
}
let panel = document.getElementById("social-notification-panel");
// load the status button for provider 2
let provider = Social._getProviderFromOrigin(manifests[1].origin);
let id = SocialStatus._toolbarHelper.idFromOrgin(provider.origin);
let btn = document.getElementById(id)
ok(btn, "got a status button");
// cheat a little, we want the iframe for the status button to be created,
// not testing the statusbutton itself here.
SocialStatus._attachNotificatonPanel(btn, provider);
let numIcons = Object.keys(Social.provider.ambientNotificationIcons).length;
let ambientIcons = document.querySelectorAll("#social-toolbar-item > toolbarbutton[type='badged']");
is(numIcons, ambientIcons.length, "all ambient icons exist");
is(panel.childNodes.length, ambientIcons.length + 1, "frames all exist");
next();
// we need to wait until after social:profile-changed has completed
waitForNotification("social:profile-changed", function() {
// let the notifications finish first
executeSoon(function() {
let icons = document.querySelectorAll("#social-toolbar-item > toolbarbutton[type='badged']");
is(icons.length, 0, "ambient icons have been removed");
is(panel.childNodes.length, 1, "frame still exists");
next();
});
});
Social.provider.updateUserProfile({});
},
testMenuitemsExist: function(next) {
let toggleSidebarMenuitems = document.getElementsByClassName("social-toggle-sidebar-menuitem");
@ -194,5 +230,5 @@ var tests = {
is(cmd.getAttribute("checked"), enabled ? "true" : "false");
Services.prefs.clearUserPref("social.toast-notifications.enabled");
next();
},
}
}

View File

@ -298,6 +298,14 @@ function checkSocialUI(win) {
is(numGoodTests, numTests, "The Social UI tests succeeded.")
}
function waitForNotification(topic, cb) {
function observer(subject, topic, data) {
Services.obs.removeObserver(observer, topic);
cb();
}
Services.obs.addObserver(observer, topic, false);
}
// blocklist testing
function updateBlocklist(aCallback) {
var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]

View File

@ -0,0 +1,180 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
/* 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/. */
/**
* Handles the download progress indicator in the taskbar.
*/
"use strict";
this.EXPORTED_SYMBOLS = [
"DownloadsTaskbar",
];
////////////////////////////////////////////////////////////////////////////////
//// Globals
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "gWinTaskbar", function () {
if (!("@mozilla.org/windows-taskbar;1" in Cc)) {
return null;
}
let winTaskbar = Cc["@mozilla.org/windows-taskbar;1"]
.getService(Ci.nsIWinTaskbar);
return winTaskbar.available && winTaskbar;
});
XPCOMUtils.defineLazyGetter(this, "gMacTaskbarProgress", function () {
return ("@mozilla.org/widget/macdocksupport;1" in Cc) &&
Cc["@mozilla.org/widget/macdocksupport;1"]
.getService(Ci.nsITaskbarProgress);
});
////////////////////////////////////////////////////////////////////////////////
//// DownloadsTaskbar
/**
* Handles the download progress indicator in the taskbar.
*/
this.DownloadsTaskbar = {
/**
* Underlying DownloadSummary providing the aggregate download information, or
* null if the indicator has never been initialized.
*/
_summary: null,
/**
* nsITaskbarProgress object to which download information is dispatched.
* This can be null if the indicator has never been initialized or if the
* indicator is currently hidden on Windows.
*/
_taskbarProgress: null,
/**
* This method is called after a new browser window is opened, and ensures
* that the download progress indicator is displayed in the taskbar.
*
* On Windows, the indicator is attached to the first browser window that
* calls this method. When the window is closed, the indicator is moved to
* another browser window, if available, in no particular order. When there
* are no browser windows visible, the indicator is hidden.
*
* On Mac OS X, the indicator is initialized globally when this method is
* called for the first time. Subsequent calls have no effect.
*
* @param aBrowserWindow
* nsIDOMWindow object of the newly opened browser window to which the
* indicator may be attached.
*/
registerIndicator: function (aBrowserWindow)
{
if (!this._taskbarProgress) {
if (gMacTaskbarProgress) {
// On Mac OS X, we have to register the global indicator only once.
this._taskbarProgress = gMacTaskbarProgress;
// Free the XPCOM reference on shutdown, to prevent detecting a leak.
Services.obs.addObserver(() => {
this._taskbarProgress = null;
gMacTaskbarProgress = null;
}, "quit-application-granted", false);
} else if (gWinTaskbar) {
// On Windows, the indicator is currently hidden because we have no
// previous browser window, thus we should attach the indicator now.
this._attachIndicator(aBrowserWindow);
} else {
// The taskbar indicator is not available on this platform.
return;
}
}
// Ensure that the DownloadSummary object will be created asynchronously.
if (!this._summary) {
Downloads.getSummary(Downloads.ALL).then(summary => {
// In case the method is re-entered, we simply ignore redundant
// invocations of the callback, instead of keeping separate state.
if (this._summary) {
return;
}
this._summary = summary;
this._summary.addView(this);
});
}
},
/**
* On Windows, attaches the taskbar indicator to the specified browser window.
*/
_attachIndicator: function (aWindow)
{
// Activate the indicator on the specified window.
let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIXULWindow).docShell;
this._taskbarProgress = gWinTaskbar.getTaskbarProgress(docShell);
// If the DownloadSummary object has already been created, we should update
// the state of the new indicator, otherwise it will be updated as soon as
// the DownloadSummary view is registered.
if (this._summary) {
this.onSummaryChanged();
}
aWindow.addEventListener("unload", () => {
// Locate another browser window, excluding the one being closed.
let browserWindow = RecentWindow.getMostRecentBrowserWindow();
if (browserWindow) {
// Move the progress indicator to the other browser window.
this._attachIndicator(browserWindow);
} else {
// The last browser window has been closed. We remove the reference to
// the taskbar progress object so that the indicator will be registered
// again on the next browser window that is opened.
this._taskbarProgress = null;
}
}, false);
},
//////////////////////////////////////////////////////////////////////////////
//// DownloadSummary view
onSummaryChanged: function ()
{
// If the last browser window has been closed, we have no indicator anymore.
if (!this._taskbarProgress) {
return;
}
if (this._summary.allHaveStopped || this._summary.progressTotalBytes == 0) {
this._taskbarProgress.setProgressState(
Ci.nsITaskbarProgress.STATE_NO_PROGRESS, 0, 0);
} else {
// For a brief moment before completion, some download components may
// report more transferred bytes than the total number of bytes. Thus,
// ensure that we never break the expectations of the progress indicator.
let progressCurrentBytes = Math.min(this._summary.progressTotalBytes,
this._summary.progressCurrentBytes);
this._taskbarProgress.setProgressState(
Ci.nsITaskbarProgress.STATE_NORMAL,
progressCurrentBytes,
this._summary.progressTotalBytes);
}
},
};

View File

@ -13,5 +13,6 @@ EXTRA_COMPONENTS += [
EXTRA_JS_MODULES += [
'DownloadsCommon.jsm',
'DownloadsLogger.jsm',
'DownloadsTaskbar.jsm',
]

View File

@ -0,0 +1,24 @@
/* 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/. */
const {Cu} = require("chrome");
const ObservableObject = require("devtools/shared/observable-object");
const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
let store = new ObservableObject({versions:[]});
function feedStore() {
store.object.available = Devices.helperAddonInstalled;
store.object.devices = Devices.available().map(n => {
return {name:n}
});
}
Devices.on("register", feedStore);
Devices.on("unregister", feedStore);
Devices.on("addon-status-updated", feedStore);
feedStore();
module.exports = store;

View File

@ -8,6 +8,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/devtools/gDevTools.jsm");
const {Simulator} = Cu.import("resource://gre/modules/devtools/Simulator.jsm")
const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const {require} = devtools;
@ -15,6 +16,7 @@ const {ConnectionManager, Connection} = require("devtools/client/connection-mana
const ConnectionStore = require("devtools/app-manager/connection-store");
const DeviceStore = require("devtools/app-manager/device-store");
const simulatorsStore = require("devtools/app-manager/simulators-store");
const adbStore = require("devtools/app-manager/builtin-adb-store");
let UI = {
init: function() {
@ -46,6 +48,7 @@ let UI = {
"device": new DeviceStore(this.connection),
"connection": new ConnectionStore(this.connection),
"simulators": simulatorsStore,
"adb": adbStore
});
let pre = document.querySelector("#logs > pre");
@ -109,7 +112,7 @@ let UI = {
},
installSimulator: function() {
let url = Services.prefs.getCharPref("devtools.appmanager.simulatorInstallPage");
let url = "https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Simulator";
window.open(url);
},
@ -142,4 +145,13 @@ let UI = {
});
document.body.classList.remove("show-simulators");
},
connectToAdbDevice: function(name) {
let device = Devices.getByName(name);
device.connect().then((port) => {
this.connection.host = "localhost";
this.connection.port = port;
this.connect();
});
},
}

View File

@ -34,10 +34,23 @@
<div id="banner-disconnected" class="banner">
<div class="connected-indicator"></div>
<div class="banner-box">
<div class="banner-content">
<span>&connection.notConnected;</span>
<button class="action-primary left" onclick="UI.connect()" id="connect-button" template='{"type":"localizedContent","property":"connection.connectTo","paths":["connection.host","connection.port"]}' title="&connection.connectTooltip;"></button>
<button class="right" onclick="UI.editConnectionParameters()" title="&connection.changeHostAndPortTooltip;">&connection.changeHostAndPort;</button>
<div class="banner-content" template='{"type":"attribute","path":"adb.available","name":"adb-available"}'>
<span>&connection.notConnected2;</span>
<div id="connection-manual">
<button class="action-primary left" onclick="UI.connect()" id="connect-button" template='{"type":"localizedContent","property":"connection.connectTo","paths":["connection.host","connection.port"]}'></button>
<button class="right" onclick="UI.editConnectionParameters()">&connection.changeHostAndPort;</button>
<button class="action-primary left" onclick="UI.connect()" id="connect-button" template='{"type":"localizedContent","property":"connection.connectTo","paths":["connection.host","connection.port"]}' title="&connection.connectTooltip;"></button>
<button class="right" onclick="UI.editConnectionParameters()" title="&connection.changeHostAndPortTooltip;">&connection.changeHostAndPort;</button>
</div>
<div id="connection-assisted" template='{"type":"attribute","path":"adb.devices.length","name":"device-count"}'>
<div id="connection-found-device">
<span>&connection.connectTo;</span>
<span template-loop='{"arrayPath":"adb.devices","childSelector":"#adb-devices-template"}'></span>
</div>
<div id="connection-no-device">
<span>&connection.noDeviceFound;</span>
</div>
</div>
<div id="start-simulator-box">
<span>&connection.or;</span>
<button id="start-simulator-button" class="action-primary" onclick="UI.showSimulatorList()" title="&connection.startSimulatorTooltip;">&connection.startSimulator;</button>
@ -119,6 +132,14 @@
</span>
</template>
<template id="adb-devices-template">
<span>
<button class="adb-device action-primary" onclick="UI.connectToAdbDevice(this.dataset.name)" template='{"type":"attribute","path":"name","name":"data-name"}'>
<span template='{"type":"textContent", "path":"name"}'></span>
</button>
</span>
</template>
<script type="application/javascript;version=1.8" src="utils.js"></script>
<script type="application/javascript;version=1.8" src="template.js"></script>
<script type="application/javascript;version=1.8" src="connection-footer.js"></script>

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html [
<!ENTITY % appMgrDTD SYSTEM "chrome://browser/locale/devtools/app-manager.dtd" >
%appMgrDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<base href="chrome://browser/content/devtools/app-manager/"></base>
<title>&help.title;</title>
<link rel="stylesheet" href="chrome://browser/skin/devtools/app-manager/help.css" type="text/css"/>
</head>
<body>
<h1>&help.title;</h1>
<p>&help.intro;</p>
<p>&help.usefullLinks;</p>
<ul>
<li id="linkToAppMgrDoc">&help.linkToAppMgrDoc;</li>
<li id="linkToConfiguringDevice">&help.linkToConfiguringDevice;</li>
<li id="linkToTroubleShooting">&help.linkToTroubleShooting;</li>
<li id="linkToSimulatorAddon">&help.linkToSimulatorAddon;</li>
<li id="linkToAdbHelperAddon">&help.linkToAdbHelperAddon;</li>
</ul>
<button id="close-button" onclick="closeHelp()">&help.close;</button>
</body>
<script type="application/javascript;version=1.8">
function closeHelp() {
window.parent.postMessage(JSON.stringify({name:"closeHelp"}), "*");
}
let a;
let link_usingAppMgr = "https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager";
let link_configuringDevice = "https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Configuring_device";
let link_troubleShooting = "https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Troubleshooting";
let link_installSimulator = "https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Simulator";
let link_installAdbHelper = "https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Adb_Helper_Add-on";
a = document.querySelector("#linkToAppMgrDoc > a");
a.target = "mdn";
a.href = link_usingAppMgr;
a = document.querySelector("#linkToConfiguringDevice > a");
a.target = "mdn";
a.href = link_configuringDevice;
a = document.querySelector("#linkToTroubleShooting > a");
a.target = "mdn";
a.href = link_troubleShooting;
a = document.querySelector("#linkToSimulatorAddon> a");
a.target = "mdn";
a.href = link_installSimulator;
a = document.querySelector("#linkToAdbHelperAddon > a");
a.target = "mdn";
a.href = link_installAdbHelper;
</script>
</html>

View File

@ -7,21 +7,29 @@ Cu.import("resource:///modules/devtools/gDevTools.jsm");
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const {require} = devtools;
const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
const prefs = require('sdk/preferences/service');
let connection;
window.addEventListener("message", function(event) {
try {
let json = JSON.parse(event.data);
if (json.name == "connection") {
let cid = +json.cid;
for (let c of ConnectionManager.connections) {
if (c.uid == cid) {
connection = c;
onNewConnection();
break;
switch (json.name) {
case "connection":
let cid = +json.cid;
for (let c of ConnectionManager.connections) {
if (c.uid == cid) {
connection = c;
onNewConnection();
break;
}
}
}
break;
case "closeHelp":
selectTab("projects");
break;
default:
Cu.reportError("Unknown message: " + json.name);
}
} catch(e) { Cu.reportError(e); }
@ -45,10 +53,18 @@ function selectTab(id) {
for (let type of ["button", "panel"]) {
let oldSelection = document.querySelector("." + type + "[selected]");
let newSelection = document.querySelector("." + id + "-" + type);
if (!newSelection) continue;
if (oldSelection) oldSelection.removeAttribute("selected");
newSelection.setAttribute("selected", "true");
if (newSelection) newSelection.setAttribute("selected", "true");
}
if (id != "help") {
// Might be the first time the user is accessing the actual app manager
prefs.set("devtools.appmanager.firstrun", false);
}
}
selectTab("projects");
let firstRun = prefs.get("devtools.appmanager.firstrun");
if (firstRun) {
selectTab("help");
} else {
selectTab("projects");
}

View File

@ -20,15 +20,18 @@
width="800" height="600"
persist="screenX screenY width height sizemode">
<vbox flex="1">
<vbox id="root" flex="1">
<hbox id="content" flex="1">
<vbox id="tabs">
<button class="button projects-button" onclick="selectTab('projects')">&index.projects2;</button>
<button class="button device-button" onclick="selectTab('device')">&index.device2;</button>
<spacer flex="1"/>
<button class="button help-button" onclick="selectTab('help')">&index.help;</button>
</vbox>
<hbox id="tab-panels" flex="1">
<iframe flex="1" class="panel projects-panel" src="chrome://browser/content/devtools/app-manager/projects.xhtml"/>
<iframe flex="1" class="panel device-panel" src="chrome://browser/content/devtools/app-manager/device.xhtml"/>
<iframe flex="1" class="panel help-panel" src="chrome://browser/content/devtools/app-manager/help.xhtml"></iframe>
</hbox>
</hbox>
<iframe id="connection-footer" src="chrome://browser/content/devtools/app-manager/connection-footer.xhtml"></iframe>

View File

@ -116,41 +116,59 @@ let UI = {
validate: function(project) {
let validation = new AppValidator(project);
validation.validate()
.then(function () {
if (validation.manifest) {
project.name = validation.manifest.name;
project.icon = UI._getLocalIconURL(project, validation.manifest);
project.manifest = validation.manifest;
}
return validation.validate()
.then(function () {
if (validation.manifest) {
project.name = validation.manifest.name;
project.icon = UI._getLocalIconURL(project, validation.manifest);
project.manifest = validation.manifest;
}
project.validationStatus = "valid";
project.validationStatus = "valid";
if (validation.warnings.length > 0) {
project.warningsCount = validation.warnings.length;
project.warnings = validation.warnings.join(",\n ");
project.validationStatus = "warning";
} else {
project.warnings = "";
project.warningsCount = 0;
}
if (validation.warnings.length > 0) {
project.warningsCount = validation.warnings.length;
project.warnings = validation.warnings.join(",\n ");
project.validationStatus = "warning";
} else {
project.warnings = "";
project.warningsCount = 0;
}
if (validation.errors.length > 0) {
project.errorsCount = validation.errors.length;
project.errors = validation.errors.join(",\n ");
project.validationStatus = "error";
} else {
project.errors = "";
project.errorsCount = 0;
}
if (validation.errors.length > 0) {
project.errorsCount = validation.errors.length;
project.errors = validation.errors.join(",\n ");
project.validationStatus = "error";
} else {
project.errors = "";
project.errorsCount = 0;
}
});
});
},
update: function(location) {
update: function(button, location) {
button.disabled = true;
let project = AppProjects.get(location);
this.validate(project);
this.validate(project)
.then(() => {
// Install the app to the device if we are connected,
// and there is no error
if (project.errorsCount == 0 && this.listTabsResponse) {
return this.install(project);
}
})
.then(
() => {
button.disabled = false;
},
(res) => {
button.disabled = false;
let message = res.error + ": " + res.message;
alert(message);
this.connection.log(message);
});
},
remove: function(location) {
@ -165,11 +183,7 @@ let UI = {
}
},
install: function(button, location) {
button.dataset.originalTextContent = button.textContent;
button.textContent = Utils.l10n("project.installing");
button.disabled = true;
let project = AppProjects.get(location);
install: function(project) {
let install;
if (project.type == "packaged") {
install = installPackaged(this.connection.client, this.listTabsResponse.webappsActor, project.location, project.packagedAppOrigin);
@ -183,43 +197,37 @@ let UI = {
};
install = installHosted(this.connection.client, this.listTabsResponse.webappsActor, appId, metadata, project.manifest);
}
install.then(function () {
button.disabled = false;
button.textContent = Utils.l10n("project.installed");
setTimeout(function() {
button.textContent = button.dataset.originalTextContent;
}, 1500);
},
function (res) {
button.disabled = false;
let message = res.error + ": " + res.message;
alert(message);
this.connection.log(message);
});
return install;
},
start: function(location) {
let project = AppProjects.get(location);
start: function(project) {
let deferred = promise.defer();
let request = {
to: this.listTabsResponse.webappsActor,
type: "launch",
manifestURL: this._getProjectManifestURL(project)
};
this.connection.client.request(request, (res) => {
if (res.error)
deferred.reject(res.error);
else
deferred.resolve(res);
});
return deferred.promise;
},
stop: function(location) {
let project = AppProjects.get(location);
let deferred = promise.defer();
let request = {
to: this.listTabsResponse.webappsActor,
type: "close",
manifestURL: this._getProjectManifestURL(project)
};
this.connection.client.request(request, (res) => {
promive.resolve(res);
});
return deferred.promise;
},
_getTargetForApp: function(manifest) { // FIXME <- will be implemented in bug 912476
@ -252,8 +260,39 @@ let UI = {
return deferred.promise;
},
openToolbox: function(location) {
debug: function(button, location) {
button.disabled = true;
let project = AppProjects.get(location);
// First try to open the app
this.start(project)
.then(
null,
(error) => {
// If not installed, install and open it
if (error == "NO_SUCH_APP") {
return this.install(project)
.then(() => this.start(project));
} else {
throw error;
}
})
.then(() => {
// Finally, when it's finally opened, display the toolbox
return this.openToolbox(project)
})
.then(() => {
// And only when the toolbox is opened, release the button
button.disabled = false;
},
(msg) => {
button.disabled = false;
alert(msg);
this.connection.log(msg);
});
},
openToolbox: function(project) {
let deferred = promise.defer();
let manifest = this._getProjectManifestURL(project);
this._getTargetForApp(manifest).then((target) => {
gDevTools.showToolbox(target,
@ -262,11 +301,12 @@ let UI = {
this.connection.once(Connection.Events.DISCONNECTED, () => {
toolbox.destroy();
});
deferred.resolve();
});
}, console.error);
}, deferred.reject);
return deferred.promise;
},
reveal: function(location) {
let project = AppProjects.get(location);
if (project.type == "packaged") {

View File

@ -70,11 +70,8 @@
</div>
</div>
<div class="project-buttons">
<button class="project-button-refresh" onclick="UI.update(this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}'>&projects.reloadFiles;</button>
<button class="device-action project-button-install" onclick="UI.install(this, this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}'>&projects.installApp;</button>
<button class="device-action project-button-start" onclick="UI.start(this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}'>&projects.startApp;</button>
<button class="device-action project-button-stop" onclick="UI.stop(this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}'>&projects.stopApp;</button>
<button class="device-action project-button-debug" onclick="UI.openToolbox(this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}'>&projects.debugApp;</button>
<button class="project-button-update" onclick="UI.update(this, this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}' title="&projects.updateAppTooltip;">&projects.updateApp;</button>
<button class="device-action project-button-debug" onclick="UI.debug(this, this.dataset.location)" template='{"type":"attribute","path":"location","name":"data-location"}' title="&projects.debugAppTooltip;">&projects.debugApp;</button>
</div>
<div class="project-errors" template='{"type":"textContent","path":"errors"}'></div>
<div class="project-warnings" template='{"type":"textContent","path":"warnings"}'></div>

View File

@ -1270,6 +1270,7 @@ Breakpoints.prototype = {
*/
_added: new Map(),
_removing: new Map(),
_disabled: new Map(),
/**
* Adds the source editor breakpoint handlers.
@ -1362,7 +1363,7 @@ Breakpoints.prototype = {
* are received via the _onNewSource and _onSourcesAdded event listeners.
*/
updateEditorBreakpoints: function() {
for (let [, breakpointPromise] of this._added) {
for (let breakpointPromise of this._addedOrDisabled) {
breakpointPromise.then(aBreakpointClient => {
let currentSourceUrl = DebuggerView.Sources.selectedValue;
let breakpointUrl = aBreakpointClient.location.url;
@ -1382,7 +1383,7 @@ Breakpoints.prototype = {
* _onSourcesAdded event listeners.
*/
updatePaneBreakpoints: function() {
for (let [, breakpointPromise] of this._added) {
for (let breakpointPromise of this._addedOrDisabled) {
breakpointPromise.then(aBreakpointClient => {
let container = DebuggerView.Sources;
let breakpointUrl = aBreakpointClient.location.url;
@ -1435,7 +1436,7 @@ Breakpoints.prototype = {
let deferred = promise.defer();
// Remember the breakpoint initialization promise in the store.
let identifier = this._getIdentifier(aLocation);
let identifier = this.getIdentifier(aLocation);
this._added.set(identifier, deferred.promise);
// Try adding the breakpoint.
@ -1445,7 +1446,7 @@ Breakpoints.prototype = {
if (aResponse.actualLocation) {
// Remember the initialization promise for the new location instead.
let oldIdentifier = identifier;
let newIdentifier = this._getIdentifier(aResponse.actualLocation);
let newIdentifier = identifier = this.getIdentifier(aResponse.actualLocation);
this._added.delete(oldIdentifier);
this._added.set(newIdentifier, deferred.promise);
@ -1455,6 +1456,11 @@ Breakpoints.prototype = {
aBreakpointClient.location = aResponse.actualLocation;
}
// By default, new breakpoints are always enabled. Disabled breakpoints
// are, in fact, removed from the server but preserved in the frontend,
// so that they may not be forgotten across target navigations.
this._disabled.delete(identifier);
// Preserve information about the breakpoint's line text, to display it
// in the sources pane without requiring fetching the source (for example,
// after the target navigated). Note that this will get out of sync
@ -1507,7 +1513,7 @@ Breakpoints.prototype = {
let deferred = promise.defer();
// Remember the breakpoint removal promise in the store.
let identifier = this._getIdentifier(aLocation);
let identifier = this.getIdentifier(aLocation);
this._removing.set(identifier, deferred.promise);
// Retrieve the corresponding breakpoint client first.
@ -1521,6 +1527,15 @@ Breakpoints.prototype = {
return void this._removing.delete(identifier);
}
// When a breakpoint is removed, the frontend may wish to preserve some
// details about it, so that it can be easily re-added later. In such
// cases, breakpoints are marked and stored as disabled, so that they
// may not be forgotten across target navigations.
if (aOptions.rememberDisabled) {
aBreakpointClient.disabled = true;
this._disabled.set(identifier, promise.resolve(aBreakpointClient));
}
// Forget both the initialization and removal promises from the store.
this._added.delete(identifier);
this._removing.delete(identifier);
@ -1538,7 +1553,7 @@ Breakpoints.prototype = {
},
/**
* Removes all breakpoints.
* Removes all the currently enabled breakpoints.
*
* @return object
* A promise that is resolved after all breakpoints are removed, or
@ -1576,8 +1591,8 @@ Breakpoints.prototype = {
* Information about the breakpoint to be shown.
* This object must have the following properties:
* - location: the breakpoint's source location and line number
* - disabled: the breakpoint's disabled state, boolean
* - text: the breakpoint's line text to be displayed
* - actor: the breakpoint's corresponding actor id
* @param object aOptions [optional]
* @see DebuggerController.Breakpoints.addBreakpoint
*/
@ -1586,7 +1601,7 @@ Breakpoints.prototype = {
let location = aBreakpointData.location;
// Update the editor if required.
if (!aOptions.noEditorUpdate) {
if (!aOptions.noEditorUpdate && !aBreakpointData.disabled) {
if (location.url == currentSourceUrl) {
DebuggerView.editor.addBreakpoint(location.line - 1);
}
@ -1622,6 +1637,16 @@ Breakpoints.prototype = {
}
},
/**
* Gets all Promises for the BreakpointActor client objects that are
* either enabled (added to the server) or disabled (removed from the server,
* but for which some details are preserved).
*/
get _addedOrDisabled() {
for (let [, value] of this._added) yield value;
for (let [, value] of this._disabled) yield value;
},
/**
* Get a Promise for the BreakpointActor client object which is already added
* or currently being added at the given location.
@ -1633,7 +1658,7 @@ Breakpoints.prototype = {
* null if no breakpoint was found.
*/
_getAdded: function(aLocation) {
return this._added.get(this._getIdentifier(aLocation));
return this._added.get(this.getIdentifier(aLocation));
},
/**
@ -1647,7 +1672,7 @@ Breakpoints.prototype = {
* null if no breakpoint was found.
*/
_getRemoving: function(aLocation) {
return this._removing.get(this._getIdentifier(aLocation));
return this._removing.get(this.getIdentifier(aLocation));
},
/**
@ -1659,7 +1684,7 @@ Breakpoints.prototype = {
* @return string
* The identifier string.
*/
_getIdentifier: function(aLocation) {
getIdentifier: function(aLocation) {
return aLocation.url + ":" + aLocation.line;
}
};

View File

@ -135,18 +135,18 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
* Information about the breakpoint to be shown.
* This object must have the following properties:
* - location: the breakpoint's source location and line number
* - disabled: the breakpoint's disabled state, boolean
* - text: the breakpoint's line text to be displayed
* - actor: the breakpoint's corresponding actor id
* @param object aOptions [optional]
* @see DebuggerController.Breakpoints.addBreakpoint
*/
addBreakpoint: function(aBreakpointData, aOptions = {}) {
let { location, actor } = aBreakpointData;
let { location, disabled } = aBreakpointData;
// Make sure we're not duplicating anything. If a breakpoint at the
// specified source url and line already exists, just enable it.
// specified source url and line already exists, just toggle it.
if (this.getBreakpoint(location)) {
this.enableBreakpoint(location, { id: actor });
this[disabled ? "disableBreakpoint" : "enableBreakpoint"](location);
return;
}
@ -220,17 +220,18 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
/**
* Returns all breakpoints which are not at the specified source url and line.
*
* @param string aId
* The original breakpoint client actor.
* @param object aLocation [optional]
* @see DebuggerController.Breakpoints.addBreakpoint
* @param array aStore [optional]
* A list in which to store the corresponding breakpoints.
* @return array
* The corresponding breakpoints if found, an empty array otherwise.
*/
getOtherBreakpoints: function(aId, aStore = []) {
getOtherBreakpoints: function(aLocation = {}, aStore = []) {
for (let source in this) {
for (let breakpointItem in source) {
if (breakpointItem.attachment.actor != aId) {
let { url, line } = breakpointItem.attachment;
if (url != aLocation.url || line != aLocation.line) {
aStore.push(breakpointItem);
}
}
@ -245,7 +246,6 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
* @see DebuggerController.Breakpoints.addBreakpoint
* @param object aOptions [optional]
* Additional options or flags supported by this operation:
* - id: a new id to be applied to the corresponding element node
* - silent: pass true to not update the checkbox checked state;
* this is usually necessary when the checked state will
* be updated automatically (e.g: on a checkbox click).
@ -265,15 +265,12 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
// Update the corresponding menu items to reflect the enabled state.
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let enableSelfId = prefix + "enableSelf-" + attachment.actor + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + attachment.actor + "-menuitem";
let identifier = DebuggerController.Breakpoints.getIdentifier(attachment);
let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
document.getElementById(enableSelfId).setAttribute("hidden", "true");
document.getElementById(disableSelfId).removeAttribute("hidden");
// Set a new id to the corresponding breakpoint element if required.
if (aOptions.id) {
attachment.view.container.id = "breakpoint-" + aOptions.id;
}
// Update the checkbox state if necessary.
if (!aOptions.silent) {
attachment.view.checkbox.setAttribute("checked", "true");
@ -312,8 +309,9 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
// Update the corresponding menu items to reflect the disabled state.
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let enableSelfId = prefix + "enableSelf-" + attachment.actor + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + attachment.actor + "-menuitem";
let identifier = DebuggerController.Breakpoints.getIdentifier(attachment);
let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
document.getElementById(enableSelfId).removeAttribute("hidden");
document.getElementById(disableSelfId).setAttribute("hidden", "true");
@ -325,7 +323,10 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
return DebuggerController.Breakpoints.removeBreakpoint(aLocation, {
// No need to update this pane, since this method is invoked because
// a breakpoint's view was interacted with.
noPaneUpdate: true
noPaneUpdate: true,
// Mark this breakpoint as being "disabled", not completely removed.
// This makes sure it will not be forgotten across target navigations.
rememberDisabled: true
});
},
@ -448,32 +449,35 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
* @param object aOptions
* A couple of options or flags supported by this operation:
* - location: the breakpoint's source location and line number
* - text: the breakpoint's line text to be displayed.
* - actor: a breakpoint identifier specified by the controller.
* - disabled: the breakpoint's disabled state, boolean
* - text: the breakpoint's line text to be displayed
* @return object
* An object containing the breakpoint container, checkbox,
* line number and line text nodes.
*/
_createBreakpointView: function(aOptions) {
let { location, disabled, text } = aOptions;
let identifier = DebuggerController.Breakpoints.getIdentifier(location);
let checkbox = document.createElement("checkbox");
checkbox.setAttribute("checked", "true");
checkbox.setAttribute("checked", !disabled);
checkbox.className = "dbg-breakpoint-checkbox";
let lineNumberNode = document.createElement("label");
lineNumberNode.className = "plain dbg-breakpoint-line";
lineNumberNode.setAttribute("value", aOptions.location.line);
lineNumberNode.setAttribute("value", location.line);
let lineTextNode = document.createElement("label");
lineTextNode.className = "plain dbg-breakpoint-text";
lineTextNode.setAttribute("value", aOptions.text);
lineTextNode.setAttribute("value", text);
lineTextNode.setAttribute("crop", "end");
lineTextNode.setAttribute("flex", "1");
let tooltip = aOptions.text.substr(0, BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH);
let tooltip = text.substr(0, BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH);
lineTextNode.setAttribute("tooltiptext", tooltip);
let container = document.createElement("hbox");
container.id = "breakpoint-" + aOptions.actor;
container.id = "breakpoint-" + identifier;
container.className = "dbg-breakpoint side-menu-widget-item-other";
container.classList.add("devtools-monospace");
container.setAttribute("align", "center");
@ -497,23 +501,24 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
/**
* Creates a context menu for a breakpoint element.
*
* @param aOptions
* @param object aOptions
* A couple of options or flags supported by this operation:
* - actor: a breakpoint identifier specified by the controller.
* - location: the breakpoint's source location and line number
* - disabled: the breakpoint's disabled state, boolean
* @return object
* An object containing the breakpoint commandset and menu popup ids.
*/
_createContextMenu: function(aOptions) {
let commandsetId = "bp-cSet-" + aOptions.actor;
let menupopupId = "bp-mPop-" + aOptions.actor;
let { location, disabled } = aOptions;
let identifier = DebuggerController.Breakpoints.getIdentifier(location);
let commandset = document.createElement("commandset");
let menupopup = document.createElement("menupopup");
commandset.id = commandsetId;
menupopup.id = menupopupId;
commandset.id = "bp-cSet-" + identifier;
menupopup.id = "bp-mPop-" + identifier;
createMenuItem.call(this, "enableSelf", true);
createMenuItem.call(this, "disableSelf");
createMenuItem.call(this, "enableSelf", !disabled);
createMenuItem.call(this, "disableSelf", disabled);
createMenuItem.call(this, "deleteSelf");
createMenuSeparator();
createMenuItem.call(this, "setConditional");
@ -531,8 +536,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
this._commandset.appendChild(commandset);
return {
commandsetId: commandsetId,
menupopupId: menupopupId
commandsetId: commandset.id,
menupopupId: menupopup.id
};
/**
@ -549,15 +554,15 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
let command = document.createElement("command");
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let commandId = prefix + aName + "-" + aOptions.actor + "-command";
let menuitemId = prefix + aName + "-" + aOptions.actor + "-menuitem";
let commandId = prefix + aName + "-" + identifier + "-command";
let menuitemId = prefix + aName + "-" + identifier + "-menuitem";
let label = L10N.getStr("breakpointMenuItem." + aName);
let func = "_on" + aName.charAt(0).toUpperCase() + aName.slice(1);
command.id = commandId;
command.setAttribute("label", label);
command.addEventListener("command", () => this[func](aOptions.actor), false);
command.addEventListener("command", () => this[func](location), false);
menuitem.id = menuitemId;
menuitem.setAttribute("command", commandId);
@ -842,69 +847,57 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
/**
* Function invoked on the "setConditional" menuitem command.
*
* @param string aId
* The original breakpoint client actor.
* @param object aLocation
* @see DebuggerController.Breakpoints.addBreakpoint
*/
_onSetConditional: function(aId) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
let attachment = targetBreakpoint.attachment;
_onSetConditional: function(aLocation) {
// Highlight the breakpoint and show a conditional expression popup.
this.highlightBreakpoint(attachment, { openPopup: true });
this.highlightBreakpoint(aLocation, { openPopup: true });
},
/**
* Function invoked on the "enableSelf" menuitem command.
*
* @param string aId
* The original breakpoint client actor.
* @param object aLocation
* @see DebuggerController.Breakpoints.addBreakpoint
*/
_onEnableSelf: function(aId) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
let attachment = targetBreakpoint.attachment;
_onEnableSelf: function(aLocation) {
// Enable the breakpoint, in this container and the controller store.
this.enableBreakpoint(attachment);
this.enableBreakpoint(aLocation);
},
/**
* Function invoked on the "disableSelf" menuitem command.
*
* @param string aId
* The original breakpoint client actor.
* @param object aLocation
* @see DebuggerController.Breakpoints.addBreakpoint
*/
_onDisableSelf: function(aId) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
let attachment = targetBreakpoint.attachment;
_onDisableSelf: function(aLocation) {
// Disable the breakpoint, in this container and the controller store.
this.disableBreakpoint(attachment);
this.disableBreakpoint(aLocation);
},
/**
* Function invoked on the "deleteSelf" menuitem command.
*
* @param string aId
* The original breakpoint client actor.
* @param object aLocation
* @see DebuggerController.Breakpoints.addBreakpoint
*/
_onDeleteSelf: function(aId) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
let attachment = targetBreakpoint.attachment;
_onDeleteSelf: function(aLocation) {
// Remove the breakpoint, from this container and the controller store.
this.removeBreakpoint(attachment);
DebuggerController.Breakpoints.removeBreakpoint(attachment);
this.removeBreakpoint(aLocation);
DebuggerController.Breakpoints.removeBreakpoint(aLocation);
},
/**
* Function invoked on the "enableOthers" menuitem command.
*
* @param string aId
* The original breakpoint client actor.
* @param object aLocation
* @see DebuggerController.Breakpoints.addBreakpoint
*/
_onEnableOthers: function(aId) {
let enableOthers = (aCallback) => {
let other = this.getOtherBreakpoints(aId);
_onEnableOthers: function(aLocation) {
let enableOthers = aCallback => {
let other = this.getOtherBreakpoints(aLocation);
let outstanding = other.map(e => this.enableBreakpoint(e.attachment));
promise.all(outstanding).then(aCallback);
}
@ -922,44 +915,44 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
/**
* Function invoked on the "disableOthers" menuitem command.
*
* @param string aId
* The original breakpoint client actor.
* @param object aLocation
* @see DebuggerController.Breakpoints.addBreakpoint
*/
_onDisableOthers: function(aId) {
let other = this.getOtherBreakpoints(aId);
other.forEach(e => this._onDisableSelf(e.attachment.actor));
_onDisableOthers: function(aLocation) {
let other = this.getOtherBreakpoints(aLocation);
other.forEach(e => this._onDisableSelf(e.attachment));
},
/**
* Function invoked on the "deleteOthers" menuitem command.
*
* @param string aId
* The original breakpoint client actor.
* @param object aLocation
* @see DebuggerController.Breakpoints.addBreakpoint
*/
_onDeleteOthers: function(aId) {
let other = this.getOtherBreakpoints(aId);
other.forEach(e => this._onDeleteSelf(e.attachment.actor));
_onDeleteOthers: function(aLocation) {
let other = this.getOtherBreakpoints(aLocation);
other.forEach(e => this._onDeleteSelf(e.attachment));
},
/**
* Function invoked on the "enableAll" menuitem command.
*/
_onEnableAll: function() {
this._onEnableOthers(null);
this._onEnableOthers(undefined);
},
/**
* Function invoked on the "disableAll" menuitem command.
*/
_onDisableAll: function() {
this._onDisableOthers(null);
this._onDisableOthers(undefined);
},
/**
* Function invoked on the "deleteAll" menuitem command.
*/
_onDeleteAll: function() {
this._onDeleteOthers(null);
this._onDeleteOthers(undefined);
},
_commandset: null,

View File

@ -15,6 +15,7 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_breadcrumbs-access.js \
browser_dbg_breakpoints-actual-location.js \
browser_dbg_breakpoints-contextmenu.js \
browser_dbg_breakpoints-disabled-reload.js \
browser_dbg_breakpoints-editor.js \
browser_dbg_breakpoints-highlight.js \
browser_dbg_breakpoints-new-script.js \

View File

@ -113,10 +113,10 @@ function test() {
is(!!breakpoint.attachment.disabled, false,
"All breakpoints should initially be enabled.");
let actor = breakpoint.attachment.actor;
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let enableSelfId = prefix + "enableSelf-" + actor + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + actor + "-menuitem";
let identifier = gBreakpoints.getIdentifier(breakpoint.attachment);
let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
is(gDebugger.document.getElementById(enableSelfId).getAttribute("hidden"), "true",
"The 'Enable breakpoint' context menu item should initially be hidden'.");
@ -151,10 +151,10 @@ function test() {
"There should be a breakpoint client available as a promise.");
});
let actor = selectedBreakpoint.attachment.actor;
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let enableSelfId = prefix + "enableSelf-" + actor + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + actor + "-menuitem";
let identifier = gBreakpoints.getIdentifier(selectedBreakpoint.attachment);
let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem";
is(gDebugger.document.getElementById(enableSelfId).getAttribute("hidden"), "true",
"The 'Enable breakpoint' context menu item should be hidden'.");
@ -176,7 +176,7 @@ function test() {
});
// Test re-disabling this breakpoint.
gSources._onEnableSelf(selectedBreakpoint.attachment.actor);
gSources._onEnableSelf(selectedBreakpoint.attachment);
is(selectedBreakpoint.attachment.disabled, false,
"The current breakpoint should now be enabled.")
@ -189,7 +189,7 @@ function test() {
});
// Test disabling this breakpoint.
gSources._onDisableSelf(selectedBreakpoint.attachment.actor);
gSources._onDisableSelf(selectedBreakpoint.attachment);
is(selectedBreakpoint.attachment.disabled, true,
"The current breakpoint should now be disabled.")
@ -305,10 +305,10 @@ function test() {
}
function disableOthers() {
gSources._onDisableOthers(gSources._selectedBreakpointItem.attachment.actor);
gSources._onDisableOthers(gSources._selectedBreakpointItem.attachment);
}
function enableOthers() {
gSources._onEnableOthers(gSources._selectedBreakpointItem.attachment.actor);
gSources._onEnableOthers(gSources._selectedBreakpointItem.attachment);
}
function disableAll() {
gSources._onDisableAll();

View File

@ -0,0 +1,115 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that disabled breakpoints survive target navigation.
*/
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
let gDebugger = aPanel.panelWin;
let gEvents = gDebugger.EVENTS;
let gEditor = gDebugger.DebuggerView.editor;
let gSources = gDebugger.DebuggerView.Sources;
let gBreakpoints = gDebugger.DebuggerController.Breakpoints;
let gBreakpointLocation = { url: EXAMPLE_URL + "code_script-switching-01.js", line: 5 };
Task.spawn(function() {
yield waitForSourceShown(aPanel, "-01.js");
yield aPanel.addBreakpoint(gBreakpointLocation);
yield ensureThreadClientState(aPanel, "resumed");
yield testWhenBreakpointEnabledAndFirstSourceShown();
yield reloadActiveTab(aPanel, gEvents.SOURCE_SHOWN);
yield testWhenBreakpointEnabledAndSecondSourceShown();
yield gSources.disableBreakpoint(gBreakpointLocation);
yield reloadActiveTab(aPanel, gEvents.SOURCE_SHOWN);
yield testWhenBreakpointDisabledAndSecondSourceShown();
yield gSources.enableBreakpoint(gBreakpointLocation);
yield reloadActiveTab(aPanel, gEvents.SOURCE_SHOWN);
yield testWhenBreakpointEnabledAndSecondSourceShown();
yield resumeDebuggerThenCloseAndFinish(aPanel);
});
function verifyView({ disabled, visible }) {
return Task.spawn(function() {
// It takes a tick for the checkbox in the SideMenuWidget and the
// gutter in the SourceEditor to get updated.
yield waitForTick();
let breakpointItem = gSources.getBreakpoint(gBreakpointLocation);
let visibleBreakpoints = gEditor.getBreakpoints();
is(!!breakpointItem.attachment.disabled, disabled,
"The selected brekapoint state was correct.");
is(breakpointItem.attachment.view.checkbox.hasAttribute("checked"), !disabled,
"The selected brekapoint's checkbox state was correct.");
// Source editor starts counting line and column numbers from 0.
let breakpointLine = breakpointItem.attachment.line - 1;
let matchedBreakpoints = visibleBreakpoints.filter(e => e.line == breakpointLine);
is(!!matchedBreakpoints.length, visible,
"The selected breakpoint's visibility in the editor was correct.");
});
}
// All the following executeSoon()'s are required to spin the event loop
// before causing the debuggee to pause, to allow functions to yield first.
function testWhenBreakpointEnabledAndFirstSourceShown() {
return Task.spawn(function() {
yield ensureSourceIs(aPanel, "-01.js");
yield verifyView({ disabled: false, visible: true });
executeSoon(() => aDebuggee.firstCall());
yield waitForDebuggerEvents(aPanel, gEvents.FETCHED_SCOPES);
yield ensureSourceIs(aPanel, "-01.js");
yield ensureCaretAt(aPanel, 5);
yield verifyView({ disabled: false, visible: true });
executeSoon(() => gDebugger.gThreadClient.resume());
yield waitForSourceAndCaretAndScopes(aPanel, "-02.js", 6);
yield verifyView({ disabled: false, visible: false });
});
}
function testWhenBreakpointEnabledAndSecondSourceShown() {
return Task.spawn(function() {
yield ensureSourceIs(aPanel, "-02.js");
yield verifyView({ disabled: false, visible: false });
executeSoon(() => aDebuggee.firstCall());
yield waitForSourceAndCaretAndScopes(aPanel, "-01.js", 5);
yield verifyView({ disabled: false, visible: true });
executeSoon(() => gDebugger.gThreadClient.resume());
yield waitForSourceAndCaretAndScopes(aPanel, "-02.js", 6);
yield verifyView({ disabled: false, visible: false });
});
}
function testWhenBreakpointDisabledAndSecondSourceShown() {
return Task.spawn(function() {
yield ensureSourceIs(aPanel, "-02.js");
yield verifyView({ disabled: true, visible: false });
executeSoon(() => aDebuggee.firstCall());
yield waitForDebuggerEvents(aPanel, gEvents.FETCHED_SCOPES);
yield ensureSourceIs(aPanel, "-02.js");
yield ensureCaretAt(aPanel, 6);
yield verifyView({ disabled: true, visible: false });
executeSoon(() => gDebugger.gThreadClient.resume());
yield waitForDebuggerEvents(aPanel, gEvents.AFTER_FRAMES_CLEARED);
yield ensureSourceIs(aPanel, "-02.js");
yield ensureCaretAt(aPanel, 6);
yield verifyView({ disabled: true, visible: false });
});
}
});
}

View File

@ -227,14 +227,14 @@ function test() {
? "Should have added a breakpoint in the pane."
: "Should have the same number of breakpoints in the pane.");
let id = "breakpoint-" + aBreakpointClient.actor;
let node = gDebugger.document.getElementById(id);
let identifier = gBreakpoints.getIdentifier(aBreakpointClient.location);
let node = gDebugger.document.getElementById("breakpoint-" + identifier);
let line = node.getElementsByClassName("dbg-breakpoint-line")[0];
let text = node.getElementsByClassName("dbg-breakpoint-text")[0];
let check = node.querySelector("checkbox");
is(node.id, id,
"Breakpoint element " + id + " found successfully.");
ok(node,
"Breakpoint element found successfully.");
is(line.getAttribute("value"), aTestData.line,
"The expected information wasn't found in the breakpoint element.");
is(text.getAttribute("value"), aTestData.text,

View File

@ -136,6 +136,8 @@ function testFocusFirst() {
}
function testRemoveTab() {
let deferred = promise.defer();
gNewWindow.close();
removeTab(gNewTab);
@ -148,7 +150,11 @@ function testRemoveTab() {
is(aResponse.selected, 0,
"The original tab is selected.");
deferred.resolve();
});
return deferred.promise;
}
function closeConnection() {

View File

@ -256,6 +256,15 @@ function performTest() {
"The 'someProp5' item should be focused.");
is(gVariablesView.getFocusedItem().expanded, true,
"The 'someProp5' item should now be expanded.");
is(gVariablesView.getFocusedItem()._store.size, 9,
"There should be 9 properties in the selected variable.");
is(gVariablesView.getFocusedItem()._enumItems.length, 7,
"There should be 7 enumerable properties in the selected variable.");
is(gVariablesView.getFocusedItem()._nonEnumItems.length, 2,
"There should be 2 non-enumerable properties in the selected variable.");
yield waitForChildNodes(gVariablesView.getFocusedItem()._enum, 7);
yield waitForChildNodes(gVariablesView.getFocusedItem()._nonenum, 2);
EventUtils.sendKey("RIGHT", gDebugger);
is(gVariablesView.getFocusedItem().name, "0",
@ -276,6 +285,15 @@ function performTest() {
"The '5' item should be focused.");
is(gVariablesView.getFocusedItem().expanded, true,
"The '5' item should now be expanded.");
is(gVariablesView.getFocusedItem()._store.size, 5,
"There should be 5 properties in the selected variable.");
is(gVariablesView.getFocusedItem()._enumItems.length, 3,
"There should be 3 enumerable properties in the selected variable.");
is(gVariablesView.getFocusedItem()._nonEnumItems.length, 2,
"There should be 2 non-enumerable properties in the selected variable.");
yield waitForChildNodes(gVariablesView.getFocusedItem()._enum, 3);
yield waitForChildNodes(gVariablesView.getFocusedItem()._nonenum, 2);
EventUtils.sendKey("RIGHT", gDebugger);
is(gVariablesView.getFocusedItem().name, "0",
@ -291,13 +309,42 @@ function performTest() {
is(gVariablesView.getFocusedItem().expanded, false,
"The '6' item should not be expanded yet.");
// Part 9: Test that the RIGHT key collapses elements as intended.
yield synthesizeKeyAndWaitForTick("VK_RIGHT", {});
is(gVariablesView.getFocusedItem().name, "6",
"The '6' item should be focused.");
is(gVariablesView.getFocusedItem().expanded, true,
"The '6' item should now be expanded.");
is(gVariablesView.getFocusedItem()._store.size, 3,
"There should be 3 properties in the selected variable.");
is(gVariablesView.getFocusedItem()._enumItems.length, 2,
"There should be 2 enumerable properties in the selected variable.");
is(gVariablesView.getFocusedItem()._nonEnumItems.length, 1,
"There should be 1 non-enumerable properties in the selected variable.");
EventUtils.sendKey("DOWN", gDebugger);
EventUtils.sendKey("DOWN", gDebugger);
EventUtils.sendKey("DOWN", gDebugger);
yield waitForChildNodes(gVariablesView.getFocusedItem()._enum, 2);
yield waitForChildNodes(gVariablesView.getFocusedItem()._nonenum, 1);
EventUtils.sendKey("RIGHT", gDebugger);
is(gVariablesView.getFocusedItem().name, "prop1",
"The 'prop1' item should be focused.");
if (gVariablesView.getFocusedItem().name != "prop1") {
gDebugger.DebuggerView.toggleInstrumentsPane({ visible: true, animated: false })
yield promise.defer().promise;
yield closeDebuggerAndFinish(gPanel);
}
EventUtils.sendKey("RIGHT", gDebugger);
is(gVariablesView.getFocusedItem().name, "prop1",
"The 'prop1' item should still be focused.");
EventUtils.sendKey("PAGE_DOWN", gDebugger);
is(gVariablesView.getFocusedItem().name, "someProp6",
"The 'someProp6' item should be focused.");
is(gVariablesView.getFocusedItem().expanded, false,
"The 'someProp6' item should not be expanded yet.");
// Part 9: Test that the RIGHT key collapses elements as intended.
EventUtils.sendKey("LEFT", gDebugger);
is(gVariablesView.getFocusedItem().name, "someProp6",
@ -457,13 +504,19 @@ function synthesizeKeyAndWaitForTick(aKey, aModifiers) {
return waitForTick();
}
function waitForTick() {
let deferred = promise.defer();
executeSoon(deferred.resolve);
return deferred.promise;
function waitForElement(aSelector, aExistence) {
return waitForPredicate(() => {
return !!gVariablesView._list.querySelector(aSelector) == aExistence;
});
}
function waitForElement(aSelector, aExistence, aInterval = 10) {
function waitForChildNodes(aTarget, aCount) {
return waitForPredicate(() => {
return aTarget.childNodes.length == aCount;
});
}
function waitForPredicate(aPredicate, aInterval = 10) {
let deferred = promise.defer();
// Poll every few milliseconds until the element is retrieved.
@ -475,8 +528,8 @@ function waitForElement(aSelector, aExistence, aInterval = 10) {
window.clearInterval(intervalID);
return;
}
// Check if the existence condition is fulfilled.
if (!!gVariablesView._list.querySelector(aSelector) != aExistence) {
// Check if the predicate condition is fulfilled.
if (!aPredicate()) {
return;
}
// We got the element, it's safe to callback.

View File

@ -205,6 +205,12 @@ function once(aTarget, aEventName, aUseCapture = false) {
return deferred.promise;
}
function waitForTick() {
let deferred = promise.defer();
executeSoon(deferred.resolve);
return deferred.promise;
}
function waitForSourceShown(aPanel, aUrl) {
return waitForDebuggerEvents(aPanel, aPanel.panelWin.EVENTS.SOURCE_SHOWN).then(aSource => {
let sourceUrl = aSource.url;

View File

@ -75,3 +75,4 @@ browser.jar:
content/browser/devtools/app-manager/projects.xhtml (app-manager/content/projects.xhtml)
content/browser/devtools/app-manager/index.xul (app-manager/content/index.xul)
content/browser/devtools/app-manager/index.js (app-manager/content/index.js)
content/browser/devtools/app-manager/help.xhtml (app-manager/content/help.xhtml)

View File

@ -429,6 +429,8 @@ social.turnOff.accesskey=T
# LOCALIZATION NOTE (social.turnOn.label): %S is the name of the social provider
social.turnOn.label=Turn on %S
social.turnOn.accesskey=T
social.turnOffAll.label=Turn off all Services
social.turnOnAll.label=Turn on all Services
# LOCALIZATION NOTE (social.markpageMenu.label): %S is the name of the social provider
social.markpageMenu.label=Save Page to %S

View File

@ -5,6 +5,7 @@
<!ENTITY index.title "App Manager">
<!ENTITY index.projects2 "Apps">
<!ENTITY index.device2 "Device">
<!ENTITY index.help "Help">
<!ENTITY device.screenshot "Screenshot">
<!ENTITY device.screenshotTooltip "Open a screenshot of the current state of the device in a new tab.">
@ -36,8 +37,9 @@
<!ENTITY connection.connectTooltip "Connect to the device.">
<!ENTITY connection.disconnect "Disconnect">
<!ENTITY connection.disconnectTooltip "Disconnect from the current device or simulator.">
<!ENTITY connection.showDeviceCtrlCenter "Click for More Details">
<!ENTITY connection.notConnected "Not Connected">
<!ENTITY connection.notConnected2 "Not Connected.">
<!ENTITY connection.connectTo "Connect to:">
<!ENTITY connection.noDeviceFound "No device found. Plug a device">
<!ENTITY connection.changeHostAndPort "Change">
<!ENTITY connection.changeHostAndPortTooltip "Change the host and port used to connect to the device. (Defaults to localhost:6000)">
<!ENTITY connection.startSimulator "Start Simulator">
@ -65,10 +67,19 @@
<!ENTITY projects.title "Local Apps">
<!ENTITY projects.appDetails "App Details">
<!ENTITY projects.removeAppFromList "Remove this app from the list of apps you are working on. This will not remove it from a device or a simulator.">
<!ENTITY projects.reloadFiles "Refresh">
<!ENTITY projects.installApp "Install">
<!ENTITY projects.startApp "Start">
<!ENTITY projects.stopApp "Stop">
<!ENTITY projects.updateApp "Update">
<!ENTITY projects.updateAppTooltip "Execute validation checks and update the app to the connected device">
<!ENTITY projects.debugApp "Debug">
<!ENTITY projects.debugAppTooltip "Open Developer Tools connected to this app">
<!ENTITY projects.hostedManifestPlaceHolder2 "http://example.com/app/manifest.webapp">
<!ENTITY projects.noProjects "No projects. Add a new packaged app below (local directory) or a hosted app (link to a manifest file).">
<!ENTITY help.title "App Manager">
<!ENTITY help.close "Close">
<!ENTITY help.intro "This tool will help you build and install web apps on compatible devices (i.e Firefox OS). The <strong>Apps</strong> tab will assist you in the validation and installation process of your app. The <strong>Device</strong> tab will give you information about the connected device. Use the bottom toolbar to connect to a device or start the simulator.">
<!ENTITY help.usefullLinks "Useful links:">
<!ENTITY help.linkToAppMgrDoc "<a>Documentation: Using the App Manager</a>">
<!ENTITY help.linkToConfiguringDevice "<a>How to setup your Firefox OS device</a>">
<!ENTITY help.linkToTroubleShooting "<a>Troubleshooting</a>">
<!ENTITY help.linkToSimulatorAddon "<a>Install Simulator Add-on</a>">
<!ENTITY help.linkToAdbHelperAddon "<a>Install Adb Helper Add-on</a>">

View File

@ -34,9 +34,8 @@ function prefObserver(subject, topic, data) {
if (enable && !Social.provider) {
// this will result in setting Social.provider
SocialService.getOrderedProviderList(function(providers) {
Social._updateProviderCache(providers);
Social.enabled = true;
Services.obs.notifyObservers(null, "social:providers-changed", null);
Social._updateProviderCache(providers);
});
} else if (!enable && Social.provider) {
Social.provider = null;
@ -168,7 +167,7 @@ this.Social = {
// Retrieve the current set of providers, and set the current provider.
SocialService.getOrderedProviderList(function (providers) {
Social._updateProviderCache(providers);
Social._updateWorkerState(true);
Social._updateWorkerState(SocialService.enabled);
});
}
@ -181,10 +180,16 @@ this.Social = {
Services.obs.notifyObservers(null, "social:" + topic, origin);
return;
}
if (topic == "provider-enabled" || topic == "provider-disabled") {
if (topic == "provider-enabled") {
Social._updateProviderCache(providers);
Social._updateWorkerState(Social.enabled);
Services.obs.notifyObservers(null, "social:" + topic, origin);
return;
}
if (topic == "provider-disabled") {
// a provider was removed from the list of providers, that does not
// affect worker state for other providers
Social._updateProviderCache(providers);
Social._updateWorkerState(true);
Services.obs.notifyObservers(null, "social:providers-changed", null);
Services.obs.notifyObservers(null, "social:" + topic, origin);
return;
}
@ -194,7 +199,6 @@ this.Social = {
Social._updateProviderCache(providers);
let provider = Social._getProviderFromOrigin(origin);
provider.reload();
Services.obs.notifyObservers(null, "social:providers-changed", null);
}
});
},
@ -210,6 +214,7 @@ this.Social = {
// Called to update our cache of providers and set the current provider
_updateProviderCache: function (providers) {
this.providers = providers;
Services.obs.notifyObservers(null, "social:providers-changed", null);
// If social is currently disabled there's nothing else to do other than
// to notify about the lack of a provider.

View File

@ -4,4 +4,4 @@
# 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/.
DIRS += ['chrome']
DIRS += ['chrome', 'unit']

View File

@ -0,0 +1,9 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += ['social']
XPCSHELL_TESTS_MANIFESTS += ['social/xpcshell.ini']

View File

@ -0,0 +1,11 @@
# 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/.
XPCSHELL_RESOURCES = \
xpcshell.ini \
head.js \
blocklist.xml \
test_social.js \
test_socialDisabledStartup.js \
$(NULL)

View File

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem blockID="s1" id="bad.com@services.mozilla.org"></emItem>
</emItems>
</blocklist>

View File

@ -0,0 +1,146 @@
/* 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/. */
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var Social, SocialService;
let manifests = [
{
name: "provider 1",
origin: "https://example1.com",
sidebarURL: "https://example1.com/sidebar/",
},
{
name: "provider 2",
origin: "https://example2.com",
sidebarURL: "https://example1.com/sidebar/",
}
];
const MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
// SocialProvider class relies on blocklisting being enabled. To enable
// blocklisting, we have to setup an app and initialize the blocklist (see
// initApp below).
const gProfD = do_get_profile();
const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
function createAppInfo(id, name, version, platformVersion) {
gAppInfo = {
// nsIXULAppInfo
vendor: "Mozilla",
name: name,
ID: id,
version: version,
appBuildID: "2007010101",
platformVersion: platformVersion ? platformVersion : "1.0",
platformBuildID: "2007010101",
// nsIXULRuntime
inSafeMode: false,
logConsoleErrors: true,
OS: "XPCShell",
XPCOMABI: "noarch-spidermonkey",
invalidateCachesOnRestart: function invalidateCachesOnRestart() {
// Do nothing
},
// nsICrashReporter
annotations: {},
annotateCrashReport: function(key, data) {
this.annotations[key] = data;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
Ci.nsIXULRuntime,
Ci.nsICrashReporter,
Ci.nsISupports])
};
var XULAppInfoFactory = {
createInstance: function (outer, iid) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return gAppInfo.QueryInterface(iid);
}
};
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
XULAPPINFO_CONTRACTID, XULAppInfoFactory);
}
function initApp() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
// prepare a blocklist file for the blocklist service
var blocklistFile = gProfD.clone();
blocklistFile.append("blocklist.xml");
if (blocklistFile.exists())
blocklistFile.remove(false);
var source = do_get_file("blocklist.xml");
source.copyTo(gProfD, "blocklist.xml");
}
function setManifestPref(manifest) {
let string = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
string.data = JSON.stringify(manifest);
Services.prefs.setComplexValue("social.manifest." + manifest.origin, Ci.nsISupportsString, string);
}
function do_wait_observer(topic, cb) {
function observer(subject, topic, data) {
Services.obs.removeObserver(observer, topic);
cb();
}
Services.obs.addObserver(observer, topic, false);
}
function do_initialize_social(enabledOnStartup, cb) {
initApp();
manifests.forEach(function (manifest) {
setManifestPref(manifest);
});
// Set both providers active and flag the first one as "current"
let activeVal = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
let active = {};
for (let m of manifests)
active[m.origin] = 1;
activeVal.data = JSON.stringify(active);
Services.prefs.setComplexValue("social.activeProviders",
Ci.nsISupportsString, activeVal);
Services.prefs.setCharPref("social.provider.current", manifests[0].origin);
Services.prefs.setBoolPref("social.enabled", enabledOnStartup);
do_register_cleanup(function() {
manifests.forEach(function (manifest) {
Services.prefs.clearUserPref("social.manifest." + manifest.origin);
});
Services.prefs.clearUserPref("social.enabled");
Services.prefs.clearUserPref("social.provider.current");
Services.prefs.clearUserPref("social.activeProviders");
});
// expecting 2 providers installed
do_wait_observer("social:providers-changed", function() {
do_check_eq(Social.providers.length, 2, "2 providers installed");
cb();
});
// import and initialize everything
SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
do_check_eq(SocialService.enabled, enabledOnStartup, "service is doing its thing");
do_check_true(SocialService.hasEnabledProviders, "Service has enabled providers");
Social = Cu.import("resource:///modules/Social.jsm", {}).Social;
do_check_false(Social.initialized, "Social is not initialized");
Social.init();
do_check_true(Social.initialized, "Social is initialized");
}

View File

@ -0,0 +1,6 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.

View File

@ -0,0 +1,34 @@
/* 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/. */
function run_test() {
// we are testing worker startup specifically
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
do_register_cleanup(function() {
Services.prefs.clearUserPref("social.allowMultipleWorkers");
});
do_test_pending();
add_test(testStartupEnabled);
add_test(testDisableAfterStartup);
do_initialize_social(true, run_next_test);
}
function testStartupEnabled() {
// wait on startup before continuing
do_check_eq(Social.providers.length, 2, "two social providers enabled");
do_check_true(Social.providers[0].enabled, "provider is enabled");
do_check_true(Social.providers[1].enabled, "provider is enabled");
run_next_test();
}
function testDisableAfterStartup() {
do_wait_observer("social:provider-set", function() {
do_check_eq(Social.enabled, false, "Social is disabled");
do_check_false(Social.providers[0].enabled, "provider is enabled");
do_check_false(Social.providers[1].enabled, "provider is enabled");
do_test_finished();
run_next_test();
});
Social.enabled = false;
}

View File

@ -0,0 +1,35 @@
/* 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/. */
function run_test() {
// we are testing worker startup specifically
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
do_register_cleanup(function() {
Services.prefs.clearUserPref("social.allowMultipleWorkers");
});
do_test_pending();
add_test(testStartupDisabled);
add_test(testEnableAfterStartup);
do_initialize_social(false, run_next_test);
}
function testStartupDisabled() {
// wait on startup before continuing
do_check_eq(Social.providers.length, 2, "two social providers available");
do_check_false(Social.providers[0].enabled, "provider is enabled");
do_check_false(Social.providers[1].enabled, "provider is enabled");
run_next_test();
}
function testEnableAfterStartup() {
do_wait_observer("social:provider-set", function() {
do_check_true(Social.enabled, "Social is enabled");
do_check_eq(Social.providers.length, 2, "two social providers available");
do_check_true(Social.providers[0].enabled, "provider is enabled");
do_check_true(Social.providers[1].enabled, "provider is enabled");
do_test_finished();
run_next_test();
});
Social.enabled = true;
}

View File

@ -0,0 +1,8 @@
[DEFAULT]
head = head.js
tail =
firefox-appdir = browser
[test_social.js]
[test_socialDisabledStartup.js]

View File

@ -230,6 +230,7 @@ browser.jar:
skin/classic/browser/devtools/app-manager/index.css (../shared/devtools/app-manager/index.css)
skin/classic/browser/devtools/app-manager/device.css (../shared/devtools/app-manager/device.css)
skin/classic/browser/devtools/app-manager/projects.css (../shared/devtools/app-manager/projects.css)
skin/classic/browser/devtools/app-manager/help.css (../shared/devtools/app-manager/help.css)
skin/classic/browser/devtools/app-manager/warning.svg (../shared/devtools/app-manager/images/warning.svg)
skin/classic/browser/devtools/app-manager/error.svg (../shared/devtools/app-manager/images/error.svg)
skin/classic/browser/devtools/app-manager/plus.svg (../shared/devtools/app-manager/images/plus.svg)

View File

@ -320,6 +320,7 @@ browser.jar:
skin/classic/browser/devtools/app-manager/index.css (../shared/devtools/app-manager/index.css)
skin/classic/browser/devtools/app-manager/device.css (../shared/devtools/app-manager/device.css)
skin/classic/browser/devtools/app-manager/projects.css (../shared/devtools/app-manager/projects.css)
skin/classic/browser/devtools/app-manager/help.css (../shared/devtools/app-manager/help.css)
skin/classic/browser/devtools/app-manager/warning.svg (../shared/devtools/app-manager/images/warning.svg)
skin/classic/browser/devtools/app-manager/error.svg (../shared/devtools/app-manager/images/error.svg)
skin/classic/browser/devtools/app-manager/plus.svg (../shared/devtools/app-manager/images/plus.svg)

View File

@ -206,3 +206,17 @@ button.action-cancel {
#banner-simulators:not([simulator-count="0"]) .no-simulator {
display: none;
}
#connection-no-device,
[device-count="0"] > #connection-found-device,
#connection-manual,
#connection-assisted {
display: none;
}
#connection-found-device,
[device-count="0"] > #connection-no-device,
[adb-available="true"] > #connection-assisted,
[adb-available="false"] > #connection-manual {
display: inline;
}

View File

@ -0,0 +1,40 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
html, body {
margin: 0;
height: 100%;
}
body {
color: #555;
font-family: Lucida Grande, Helvetica, Helvetica Neue, sans-serif;
overflow: hidden;
max-width: 600px;
margin: auto;
padding: 20px 0;
background-color: #FFF;
}
button {
border: 1px solid #CCC;
padding: 5px 15px;
cursor: pointer;
background: rgba(255,255,255,0.4);
text-transform: uppercase;
color: #3498DB;
}
button:hover {
background-color: #3498DB;
color: #FFF;
}
a, a:visited {
color: rgb(39,109,163);
}
#close-button {
float: right;
}

View File

@ -1,55 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="160px" height="160px" viewBox="0 0 160 160" enable-background="new 0 0 160 160" xml:space="preserve">
<rect display="none" fill="#22272D" width="84" height="160"/>
<rect x="80.75" display="none" fill="#194866" width="84" height="160"/>
<path fill="#414042" d="M40,21.799c-2.044,0.001-6.042,6.745-7.404,13.436L28,39.83v12l3.204,0l4.467-4.467
c0.457,0.478,0.96,0.88,1.5,1.199h5.652c0.543-0.318,1.05-0.719,1.507-1.199l4.466,4.467l3.204,0v-12l-4.597-4.596
C46.042,28.544,42.044,21.799,40,21.799z M40.005,28.834c0.712,0,1.965,2,2.746,4.392c-0.846-0.157-1.747-0.244-2.686-0.244
c-0.987,0-1.933,0.099-2.815,0.271C38.03,30.849,39.289,28.834,40.005,28.834z"/>
<path fill="#414042" d="M41.436,51.63c0,1.41-1.094,2.553-1.459,2.553c-0.364,0-1.459-1.144-1.459-2.553
c0-0.546,0.099-1.051,0.266-1.466h-1.69c-0.198,0.731-0.31,1.549-0.31,2.412c0,3.108,2.411,5.627,3.215,5.627
s3.216-2.519,3.215-5.626c0-0.864-0.112-1.681-0.31-2.413l-1.734,0C41.337,50.578,41.436,51.083,41.436,51.63z"/>
<g>
<g>
<path fill="#B2B5B9" d="M40,21.799c-2.044,0.001-6.042,6.745-7.404,13.436L28,39.83v12l3.204,0l4.467-4.467
c0.457,0.478,0.96,0.88,1.5,1.199h5.652c0.543-0.318,1.05-0.719,1.507-1.199l4.466,4.467l3.204,0v-12l-4.597-4.596
C46.042,28.544,42.044,21.799,40,21.799z M40.005,28.834c0.712,0,1.965,2,2.746,4.392c-0.846-0.157-1.747-0.244-2.686-0.244
c-0.987,0-1.933,0.099-2.815,0.271C38.03,30.849,39.289,28.834,40.005,28.834z"/>
<path fill="#B2B5B9" d="M41.436,51.63c0,1.41-1.094,2.553-1.459,2.553c-0.364,0-1.459-1.144-1.459-2.553
c0-0.546,0.099-1.051,0.266-1.466h-1.69c-0.198,0.731-0.31,1.549-0.31,2.412c0,3.108,2.411,5.627,3.215,5.627
s3.216-2.519,3.215-5.626c0-0.864-0.112-1.681-0.31-2.413l-1.734,0C41.337,50.578,41.436,51.083,41.436,51.63z"/>
</g>
</g>
<g>
<path fill="#DCE8F3" d="M120,21.799c-2.044,0.001-6.042,6.745-7.404,13.436L108,39.83v12l3.204,0l4.467-4.467
c0.457,0.478,0.96,0.88,1.5,1.199h5.652c0.543-0.318,1.05-0.719,1.507-1.199l4.467,4.467l3.204,0v-12l-4.597-4.596
C126.042,28.544,122.044,21.799,120,21.799z M120.005,28.834c0.712,0,1.965,2,2.746,4.392c-0.846-0.157-1.747-0.244-2.686-0.244
c-0.987,0-1.933,0.099-2.815,0.271C118.03,30.849,119.289,28.834,120.005,28.834z"/>
<path fill="#DCE8F3" d="M121.436,51.63c0,1.41-1.094,2.553-1.459,2.553c-0.364,0-1.459-1.144-1.459-2.553
c0-0.546,0.099-1.051,0.266-1.466h-1.69c-0.198,0.731-0.31,1.549-0.31,2.412c0,3.108,2.411,5.627,3.215,5.627
s3.216-2.519,3.215-5.626c0-0.864-0.112-1.681-0.31-2.413l-1.734,0C121.337,50.578,121.436,51.083,121.436,51.63z"/>
</g>
<g>
<g>
<path fill="#B2B5B9" d="M52.5,136.667c0,2.279-1.888,4.167-4.167,4.167H31.667c-2.279,0-4.167-1.888-4.167-4.167v-33.333
c0-2.279,1.888-4.167,4.167-4.167h16.667c2.279,0,4.167,1.888,4.167,4.167V136.667z M49.375,108.542
c0-0.554-0.488-1.042-1.042-1.042H31.667c-0.553,0-1.042,0.488-1.042,1.042v22.917c0,0.554,0.488,1.042,1.042,1.042h16.667
c0.553,0,1.042-0.488,1.042-1.042V108.542z M42.604,103.333h-5.208c-0.293,0-0.521,0.228-0.521,0.521
c0,0.293,0.228,0.521,0.521,0.521h5.208c0.293,0,0.521-0.228,0.521-0.521C43.125,103.561,42.897,103.333,42.604,103.333z
M40,134.062c-1.432,0-2.604,1.171-2.604,2.604c0,1.433,1.172,2.604,2.604,2.604s2.604-1.171,2.604-2.604
C42.604,135.234,41.432,134.062,40,134.062z"/>
</g>
</g>
<g>
<path fill="#DCE8F3" d="M132.5,136.667c0,2.279-1.888,4.167-4.167,4.167h-16.667c-2.279,0-4.167-1.888-4.167-4.167v-33.333
c0-2.279,1.888-4.167,4.167-4.167h16.667c2.279,0,4.167,1.888,4.167,4.167V136.667z M129.375,108.542
c0-0.554-0.488-1.042-1.042-1.042h-16.667c-0.553,0-1.042,0.488-1.042,1.042v22.917c0,0.554,0.488,1.042,1.042,1.042h16.667
c0.553,0,1.042-0.488,1.042-1.042V108.542z M122.604,103.333h-5.208c-0.293,0-0.521,0.228-0.521,0.521
c0,0.293,0.228,0.521,0.521,0.521h5.208c0.293,0,0.521-0.228,0.521-0.521C123.125,103.561,122.897,103.333,122.604,103.333z
M120,134.062c-1.432,0-2.604,1.171-2.604,2.604c0,1.433,1.172,2.604,2.604,2.604s2.604-1.171,2.604-2.604
C122.604,135.234,121.432,134.062,120,134.062z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="160px" height="240px" viewBox="0 0 160 240" enable-background="new 0 0 160 240" xml:space="preserve">
<rect y="40" display="none" fill="#22272D" width="84" height="160"/>
<rect x="80.75" y="40" display="none" fill="#194866" width="84" height="160"/>
<path fill="#414042" d="M40,21.149c-2.044,0.001-6.042,6.745-7.404,13.436L28,39.181v12l3.204,0l4.467-4.466
c0.457,0.478,0.96,0.88,1.5,1.199h5.652c0.543-0.318,1.05-0.719,1.507-1.199l4.466,4.466l3.204,0v-12l-4.597-4.596
C46.042,27.895,42.044,21.149,40,21.149z M40.005,28.185c0.712,0,1.965,2,2.746,4.392c-0.846-0.157-1.747-0.244-2.686-0.244
c-0.987,0-1.933,0.099-2.815,0.271C38.03,30.199,39.289,28.185,40.005,28.185z"/>
<path fill="#414042" d="M41.436,50.98c0,1.41-1.094,2.553-1.459,2.553c-0.364,0-1.459-1.144-1.459-2.553
c0-0.546,0.099-1.051,0.266-1.466h-1.69c-0.198,0.731-0.31,1.549-0.31,2.412c0,3.108,2.411,5.627,3.215,5.627
s3.216-2.519,3.215-5.626c0-0.864-0.112-1.681-0.31-2.413l-1.734,0C41.337,49.929,41.436,50.434,41.436,50.98z"/>
<g>
<g>
<path fill="#B2B5B9" d="M40,21.149c-2.044,0.001-6.042,6.745-7.404,13.436L28,39.181v12l3.204,0l4.467-4.466
c0.457,0.478,0.96,0.88,1.5,1.199h5.652c0.543-0.318,1.05-0.719,1.507-1.199l4.466,4.466l3.204,0v-12l-4.597-4.596
C46.042,27.895,42.044,21.149,40,21.149z M40.005,28.185c0.712,0,1.965,2,2.746,4.392c-0.846-0.157-1.747-0.244-2.686-0.244
c-0.987,0-1.933,0.099-2.815,0.271C38.03,30.199,39.289,28.185,40.005,28.185z"/>
<path fill="#B2B5B9" d="M41.436,50.98c0,1.41-1.094,2.553-1.459,2.553c-0.364,0-1.459-1.144-1.459-2.553
c0-0.546,0.099-1.051,0.266-1.466h-1.69c-0.198,0.731-0.31,1.549-0.31,2.412c0,3.108,2.411,5.627,3.215,5.627
s3.216-2.519,3.215-5.626c0-0.864-0.112-1.681-0.31-2.413l-1.734,0C41.337,49.929,41.436,50.434,41.436,50.98z"/>
</g>
</g>
<g>
<path fill="#DCE8F3" d="M120,21.149c-2.044,0.001-6.042,6.745-7.404,13.436L108,39.181v12l3.204,0l4.467-4.466
c0.457,0.478,0.96,0.88,1.5,1.199h5.652c0.543-0.318,1.05-0.719,1.507-1.199l4.467,4.466l3.204,0v-12l-4.597-4.596
C126.042,27.895,122.044,21.149,120,21.149z M120.005,28.185c0.712,0,1.965,2,2.746,4.392c-0.846-0.157-1.747-0.244-2.686-0.244
c-0.987,0-1.933,0.099-2.815,0.271C118.03,30.199,119.289,28.185,120.005,28.185z"/>
<path fill="#DCE8F3" d="M121.436,50.98c0,1.41-1.094,2.553-1.459,2.553c-0.364,0-1.459-1.144-1.459-2.553
c0-0.546,0.099-1.051,0.266-1.466h-1.69c-0.198,0.731-0.31,1.549-0.31,2.412c0,3.108,2.411,5.627,3.215,5.627
s3.216-2.519,3.215-5.626c0-0.864-0.112-1.681-0.31-2.413l-1.734,0C121.337,49.929,121.436,50.434,121.436,50.98z"/>
</g>
<g>
<g>
<path fill="#B2B5B9" d="M52.5,136.017c0,2.279-1.888,4.167-4.167,4.167H31.667c-2.279,0-4.167-1.888-4.167-4.167v-33.333
c0-2.279,1.888-4.167,4.167-4.167h16.667c2.279,0,4.167,1.888,4.167,4.167V136.017z M49.375,107.892
c0-0.554-0.488-1.042-1.042-1.042H31.667c-0.553,0-1.042,0.488-1.042,1.042v22.917c0,0.554,0.488,1.042,1.042,1.042h16.667
c0.553,0,1.042-0.488,1.042-1.042V107.892z M42.604,102.684h-5.208c-0.293,0-0.521,0.228-0.521,0.521
c0,0.293,0.228,0.521,0.521,0.521h5.208c0.293,0,0.521-0.228,0.521-0.521C43.125,102.912,42.897,102.684,42.604,102.684z
M40,133.413c-1.432,0-2.604,1.171-2.604,2.604c0,1.433,1.172,2.604,2.604,2.604s2.604-1.171,2.604-2.604
C42.604,134.585,41.432,133.413,40,133.413z"/>
</g>
</g>
<g>
<path fill="#DCE8F3" d="M132.5,136.017c0,2.279-1.888,4.167-4.167,4.167h-16.667c-2.279,0-4.167-1.888-4.167-4.167v-33.333
c0-2.279,1.888-4.167,4.167-4.167h16.667c2.279,0,4.167,1.888,4.167,4.167V136.017z M129.375,107.892
c0-0.554-0.488-1.042-1.042-1.042h-16.667c-0.553,0-1.042,0.488-1.042,1.042v22.917c0,0.554,0.488,1.042,1.042,1.042h16.667
c0.553,0,1.042-0.488,1.042-1.042V107.892z M122.604,102.684h-5.208c-0.293,0-0.521,0.228-0.521,0.521
c0,0.293,0.228,0.521,0.521,0.521h5.208c0.293,0,0.521-0.228,0.521-0.521C123.125,102.912,122.897,102.684,122.604,102.684z
M120,133.413c-1.432,0-2.604,1.171-2.604,2.604c0,1.433,1.172,2.604,2.604,2.604s2.604-1.171,2.604-2.604
C122.604,134.585,121.432,133.413,120,133.413z"/>
</g>
<g>
<path fill="#B2B5B9" d="M40,185.388c8.121,0,14.729,6.607,14.729,14.729S48.121,214.845,40,214.845s-14.729-6.607-14.729-14.729
S31.879,185.388,40,185.388 M40,182.75c-9.591,0-17.367,7.775-17.367,17.367c0,9.591,7.775,17.367,17.367,17.367
s17.367-7.775,17.367-17.367C57.367,190.525,49.591,182.75,40,182.75L40,182.75z"/>
<g>
<path fill="#B2B5B9" d="M39.565,204.504c-0.688,0-1.196-0.508-1.286-1.195l-0.299-2.57c-0.12-0.808,0.359-1.405,1.166-1.495
c2.81-0.269,4.364-1.345,4.364-3.229v-0.06c0-1.674-1.285-2.84-3.438-2.84c-1.584,0-2.87,0.568-4.065,1.645
c-0.299,0.239-0.688,0.418-1.106,0.418c-0.926,0-1.674-0.747-1.674-1.644c0-0.448,0.18-0.927,0.598-1.285
c1.584-1.495,3.587-2.481,6.337-2.481c4.185,0,7.024,2.331,7.024,6.068v0.06c0,3.767-2.72,5.47-6.038,6.038l-0.12,1.375
c-0.12,0.657-0.598,1.195-1.285,1.195H39.565z M39.565,206.687c1.226,0,2.122,0.896,2.122,2.062v0.299
c0,1.166-0.896,2.062-2.122,2.062s-2.123-0.896-2.123-2.062v-0.299C37.442,207.583,38.339,206.687,39.565,206.687z"/>
</g>
</g>
<g>
<path fill="#DCE8F3" d="M120,185.388c8.121,0,14.729,6.607,14.729,14.729s-6.607,14.729-14.729,14.729s-14.729-6.607-14.729-14.729
S111.879,185.388,120,185.388 M120,182.75c-9.591,0-17.367,7.775-17.367,17.367c0,9.591,7.775,17.367,17.367,17.367
s17.367-7.775,17.367-17.367C137.367,190.525,129.591,182.75,120,182.75L120,182.75z"/>
<g>
<path fill="#DCE8F3" d="M119.564,204.504c-0.688,0-1.195-0.508-1.285-1.195l-0.299-2.57c-0.12-0.808,0.358-1.405,1.166-1.495
c2.81-0.269,4.363-1.345,4.363-3.229v-0.06c0-1.674-1.285-2.84-3.438-2.84c-1.584,0-2.869,0.568-4.064,1.645
c-0.3,0.239-0.688,0.418-1.106,0.418c-0.927,0-1.674-0.747-1.674-1.644c0-0.448,0.18-0.927,0.598-1.285
c1.584-1.495,3.587-2.481,6.337-2.481c4.186,0,7.024,2.331,7.024,6.068v0.06c0,3.767-2.72,5.47-6.038,6.038l-0.119,1.375
c-0.12,0.657-0.598,1.195-1.285,1.195H119.564z M119.564,206.687c1.226,0,2.122,0.896,2.122,2.062v0.299
c0,1.166-0.896,2.062-2.122,2.062s-2.122-0.896-2.122-2.062v-0.299C117.442,207.583,118.339,206.687,119.564,206.687z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -67,13 +67,25 @@
background-image: url('chrome://browser/skin/devtools/app-manager/index-icons.svg');
background-position: left -85px, top left;
background-repeat: no-repeat, no-repeat;
background-size: 160px 160px, 2px 80px;
background-size: 160px 240px, 2px 80px;
}
.device-button[selected] {
background-position: right -85px, top left;
}
.help-button {
border-bottom: 0;
background-image: url('chrome://browser/skin/devtools/app-manager/index-icons.svg');
background-position: left -165px, top left;
background-repeat: no-repeat, no-repeat;
background-size: 160px 240px, 2px 80px;
}
.help-button[selected] {
background-position: right -165px, top left;
}
#connection-footer {
border-width: 0;
height: 50px;

View File

@ -22,7 +22,6 @@ body {
color: #333;
background-color: white;
font-family: Lucida Grande, Helvetica, Helvetica Neue, sans-serif;
display: flex;
overflow: hidden;
}
@ -359,31 +358,11 @@ strong {
color: #FFF;
}
.project-button-install,
.project-button-start {
color: #18BC9C
}
.project-button-install:hover,
.project-button-start:hover {
background-color: #18BC9C;
color: #FFF;
}
.project-button-stop {
color: #E74C3C;
}
.project-button-stop:hover {
background-color: #E74C3C;
color: #FFF;
}
.project-button-refresh {
.project-button-update {
color: #777;
}
.project-button-refresh:hover {
.project-button-update:hover {
background-color: #777;
color: #FFF;
}

View File

@ -257,6 +257,7 @@ browser.jar:
skin/classic/browser/devtools/app-manager/index.css (../shared/devtools/app-manager/index.css)
skin/classic/browser/devtools/app-manager/device.css (../shared/devtools/app-manager/device.css)
skin/classic/browser/devtools/app-manager/projects.css (../shared/devtools/app-manager/projects.css)
skin/classic/browser/devtools/app-manager/help.css (../shared/devtools/app-manager/help.css)
skin/classic/browser/devtools/app-manager/warning.svg (../shared/devtools/app-manager/images/warning.svg)
skin/classic/browser/devtools/app-manager/error.svg (../shared/devtools/app-manager/images/error.svg)
skin/classic/browser/devtools/app-manager/plus.svg (../shared/devtools/app-manager/images/plus.svg)
@ -531,6 +532,7 @@ browser.jar:
skin/classic/aero/browser/devtools/app-manager/index.css (../shared/devtools/app-manager/index.css)
skin/classic/aero/browser/devtools/app-manager/device.css (../shared/devtools/app-manager/device.css)
skin/classic/aero/browser/devtools/app-manager/projects.css (../shared/devtools/app-manager/projects.css)
skin/classic/aero/browser/devtools/app-manager/help.css (../shared/devtools/app-manager/help.css)
skin/classic/aero/browser/devtools/app-manager/warning.svg (../shared/devtools/app-manager/images/warning.svg)
skin/classic/aero/browser/devtools/app-manager/error.svg (../shared/devtools/app-manager/images/error.svg)
skin/classic/aero/browser/devtools/app-manager/plus.svg (../shared/devtools/app-manager/images/plus.svg)

View File

@ -325,6 +325,8 @@ BluetoothA2dpManager::HandleSinkPropertyChanged(const BluetoothSignal& aSignal)
OnDisconnect(EmptyString());
}
break;
default:
break;
}
}
@ -341,7 +343,7 @@ BluetoothA2dpManager::NotifyConnectionStatusChanged()
if (NS_FAILED(obs->NotifyObservers(this,
BLUETOOTH_A2DP_STATUS_CHANGED_ID,
mDeviceAddress.get()))) {
NS_WARNING("Failed to notify bluetooth-a2dp-status-changed observsers!");
BT_WARNING("Failed to notify bluetooth-a2dp-status-changed observsers!");
}
// Dispatch an event of status change

View File

@ -44,10 +44,15 @@ public:
virtual void OnConnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
virtual void OnDisconnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
// A2DP member functions
virtual void GetName(nsACString& aName)
{
aName.AssignLiteral("A2DP");
}
// A2DP-specific functions
void HandleSinkPropertyChanged(const BluetoothSignal& aSignal);
// AVRCP member functions
// AVRCP-specific functions
void SetAvrcpConnected(bool aConnected);
bool IsAvrcpConnected();
void UpdateMetaData(const nsAString& aTitle,

View File

@ -73,7 +73,7 @@ public:
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
NS_WARNING("Not a BluetoothNamedValue array!");
BT_WARNING("Not a BluetoothNamedValue array!");
SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
return false;
}
@ -86,7 +86,7 @@ public:
for (uint32_t i = 0; i < values.Length(); i++) {
const BluetoothValue properties = values[i].value();
if (properties.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
NS_WARNING("Not a BluetoothNamedValue array!");
BT_WARNING("Not a BluetoothNamedValue array!");
SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
return false;
}
@ -100,7 +100,7 @@ public:
nsresult rv;
nsIScriptContext* sc = mAdapterPtr->GetContextForEventHandlers(&rv);
if (!sc) {
NS_WARNING("Cannot create script context!");
BT_WARNING("Cannot create script context!");
SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
return false;
}
@ -108,7 +108,7 @@ public:
AutoPushJSContext cx(sc->GetNativeContext());
rv = nsTArrayToJSArray(cx, devices, &JsDevices);
if (!JsDevices) {
NS_WARNING("Cannot create JS array!");
BT_WARNING("Cannot create JS array!");
SetError(NS_LITERAL_STRING("BluetoothError"));
return false;
}
@ -142,7 +142,7 @@ public:
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
if (v.type() != BluetoothValue::Tbool) {
NS_WARNING("Not a boolean!");
BT_WARNING("Not a boolean!");
SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
return false;
}
@ -252,7 +252,7 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
AutoPushJSContext cx(sc->GetNativeContext());
JS::Rooted<JSObject*> uuids(cx);
if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) {
NS_WARNING("Cannot set JS UUIDs object!");
BT_WARNING("Cannot set JS UUIDs object!");
return;
}
mJsUuids = uuids;
@ -273,7 +273,7 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
JS::Rooted<JSObject*> deviceAddresses(cx);
if (NS_FAILED(nsTArrayToJSArray(cx, mDeviceAddresses,
deviceAddresses.address()))) {
NS_WARNING("Cannot set JS Devices object!");
BT_WARNING("Cannot set JS Devices object!");
return;
}
mJsDeviceAddresses = deviceAddresses;
@ -283,7 +283,7 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling adapter property: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(name));
NS_WARNING(warningMsg.get());
BT_WARNING(warningMsg.get());
#endif
}
}
@ -304,7 +304,7 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
{
InfallibleTArray<BluetoothNamedValue> arr;
BT_LOG("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
BT_LOGD("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("DeviceFound")) {
@ -359,7 +359,7 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling adapter signal: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
NS_WARNING(warningMsg.get());
BT_WARNING(warningMsg.get());
#endif
}
}
@ -389,7 +389,7 @@ BluetoothAdapter::StartStopDiscovery(bool aStart, ErrorResult& aRv)
rv = bs->StopDiscoveryInternal(results);
}
if (NS_FAILED(rv)) {
NS_WARNING("Start/Stop Discovery failed!");
BT_WARNING("Start/Stop Discovery failed!");
aRv.Throw(rv);
return nullptr;
}
@ -416,7 +416,7 @@ JS::Value
BluetoothAdapter::GetDevices(JSContext* aContext, ErrorResult& aRv)
{
if (!mJsDeviceAddresses) {
NS_WARNING("Devices not yet set!\n");
BT_WARNING("Devices not yet set!\n");
aRv.Throw(NS_ERROR_FAILURE);
return JS::NullValue();
}
@ -429,7 +429,7 @@ JS::Value
BluetoothAdapter::GetUuids(JSContext* aContext, ErrorResult& aRv)
{
if (!mJsUuids) {
NS_WARNING("UUIDs not yet set!\n");
BT_WARNING("UUIDs not yet set!\n");
aRv.Throw(NS_ERROR_FAILURE);
return JS::NullValue();
}
@ -559,7 +559,7 @@ BluetoothAdapter::PairUnpair(bool aPair, BluetoothDevice& aDevice,
rv = bs->RemoveDeviceInternal(addr, results);
}
if (NS_FAILED(rv)) {
NS_WARNING("Pair/Unpair failed!");
BT_WARNING("Pair/Unpair failed!");
aRv.Throw(rv);
return nullptr;
}
@ -599,7 +599,7 @@ BluetoothAdapter::SetPinCode(const nsAString& aDeviceAddress,
return nullptr;
}
if (!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) {
NS_WARNING("SetPinCode failed!");
BT_WARNING("SetPinCode failed!");
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
@ -627,7 +627,7 @@ BluetoothAdapter::SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey,
return nullptr;
}
if (bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) {
NS_WARNING("SetPasskeyInternal failed!");
BT_WARNING("SetPasskeyInternal failed!");
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
@ -657,7 +657,7 @@ BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress,
if (!bs->SetPairingConfirmationInternal(aDeviceAddress,
aConfirmation,
results)) {
NS_WARNING("SetPairingConfirmation failed!");
BT_WARNING("SetPairingConfirmation failed!");
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
@ -747,7 +747,7 @@ BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
BlobChild* actor =
ContentChild::GetSingleton()->GetOrCreateActorForBlob(aBlob);
if (!actor) {
NS_WARNING("Can't create actor");
BT_WARNING("Can't create actor");
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}

View File

@ -8,6 +8,7 @@
#define mozilla_dom_bluetooth_bluetoothcommon_h__
#include "mozilla/Observer.h"
#include "nsPrintfCString.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
@ -18,24 +19,38 @@ extern bool gBluetoothDebugFlag;
#undef BT_LOG
#if defined(MOZ_WIDGET_GONK)
#include <android/log.h>
#define BT_LOG(args...) \
/**
* Prints 'D'EBUG build logs, which show in DEBUG build only when
* developer setting 'Bluetooth output in adb' is enabled.
*/
#define BT_LOGD(args...) \
do { \
if (gBluetoothDebugFlag) { \
__android_log_print(ANDROID_LOG_INFO, "GeckoBluetooth", args); \
} \
} while(0)
/**
* Prints 'R'ELEASE build logs, which show in both RELEASE and DEBUG builds.
*/
#define BT_LOGR(args...) \
__android_log_print(ANDROID_LOG_INFO, "GeckoBluetooth", args) \
/**
* Prints DEBUG build warnings, which show in DEBUG build only.
*/
#define BT_WARNING(args...) \
__android_log_print(ANDROID_LOG_WARN, "GeckoBluetooth", args)
NS_WARNING(nsPrintfCString(args).get()) \
#else
#define BT_LOG(args, ...) \
#define BT_LOGD(args, ...) \
do { \
if (gBluetoothDebugFlag) { \
printf(args, ##__VA_ARGS__); \
} \
} while(0)
#define BT_LOGR(args, ...) printf(args, ##__VA_ARGS__)
#define BT_WARNING(args, ...) printf(args, ##__VA_ARGS__)
#endif

View File

@ -130,7 +130,7 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
JS::Rooted<JSObject*> uuids(cx);
if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) {
NS_WARNING("Cannot set JS UUIDs object!");
BT_WARNING("Cannot set JS UUIDs object!");
return;
}
mJsUuids = uuids;
@ -145,7 +145,7 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
JS::Rooted<JSObject*> services(cx);
if (NS_FAILED(nsTArrayToJSArray(cx, mServices, services.address()))) {
NS_WARNING("Cannot set JS Services object!");
BT_WARNING("Cannot set JS Services object!");
return;
}
mJsServices = services;
@ -154,7 +154,7 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling device property: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(name));
NS_WARNING(warningMsg.get());
BT_WARNING(warningMsg.get());
}
}
@ -175,7 +175,7 @@ BluetoothDevice::Create(nsPIDOMWindow* aWindow,
void
BluetoothDevice::Notify(const BluetoothSignal& aData)
{
BT_LOG("[D] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
BT_LOGD("[D] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("PropertyChanged")) {
@ -192,7 +192,7 @@ BluetoothDevice::Notify(const BluetoothSignal& aData)
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling device signal: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
NS_WARNING(warningMsg.get());
BT_WARNING(warningMsg.get());
#endif
}
}
@ -201,7 +201,7 @@ JS::Value
BluetoothDevice::GetUuids(JSContext* aCx, ErrorResult& aRv)
{
if (!mJsUuids) {
NS_WARNING("UUIDs not yet set!\n");
BT_WARNING("UUIDs not yet set!");
aRv.Throw(NS_ERROR_FAILURE);
return JS::NullValue();
}
@ -214,7 +214,7 @@ JS::Value
BluetoothDevice::GetServices(JSContext* aCx, ErrorResult& aRv)
{
if (!mJsServices) {
NS_WARNING("Services not yet set!\n");
BT_WARNING("Services not yet set!");
aRv.Throw(NS_ERROR_FAILURE);
return JS::Value(JSVAL_NULL);
}

View File

@ -171,7 +171,7 @@ public:
NS_ENSURE_TRUE(cx, NS_OK);
if (!aResult.isNumber()) {
NS_WARNING("'" AUDIO_VOLUME_BT_SCO_ID "' is not a number!");
BT_WARNING("'" AUDIO_VOLUME_BT_SCO_ID "' is not a number!");
return NS_OK;
}
@ -184,7 +184,7 @@ public:
NS_IMETHOD
HandleError(const nsAString& aName)
{
NS_WARNING("Unable to get value for '" AUDIO_VOLUME_BT_SCO_ID "'");
BT_WARNING("Unable to get value for '" AUDIO_VOLUME_BT_SCO_ID "'");
return NS_OK;
}
};
@ -255,7 +255,7 @@ public:
}
if (!sBluetoothHfpManager) {
NS_WARNING("BluetoothHfpManager no longer exists, cannot send ring!");
BT_WARNING("BluetoothHfpManager no longer exists, cannot send ring!");
return;
}
@ -375,7 +375,7 @@ BluetoothHfpManager::Init()
mListener = new BluetoothRilListener();
if (!mListener->StartListening()) {
NS_WARNING("Failed to start listening RIL");
BT_WARNING("Failed to start listening RIL");
return false;
}
@ -405,7 +405,7 @@ BluetoothHfpManager::Init()
BluetoothHfpManager::~BluetoothHfpManager()
{
if (!mListener->StopListening()) {
NS_WARNING("Failed to stop listening RIL");
BT_WARNING("Failed to stop listening RIL");
}
mListener = nullptr;
@ -454,7 +454,7 @@ BluetoothHfpManager::NotifyConnectionStatusChanged(const nsAString& aType)
if (NS_FAILED(obs->NotifyObservers(this, NS_ConvertUTF16toUTF8(aType).get(),
mDeviceAddress.get()))) {
NS_WARNING("Failed to notify observsers!");
BT_WARNING("Failed to notify observsers!");
}
// Dispatch an event of status change
@ -487,7 +487,7 @@ BluetoothHfpManager::NotifyDialer(const nsAString& aCommand)
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to broadcast system message to dialer");
BT_WARNING("Failed to broadcast system message to dialer");
}
}
@ -566,7 +566,7 @@ BluetoothHfpManager::HandleVoiceConnectionChanged()
JS::Value value;
voiceInfo->GetRelSignalStrength(&value);
if (!value.isNumber()) {
NS_WARNING("Failed to get relSignalStrength in BluetoothHfpManager");
BT_WARNING("Failed to get relSignalStrength in BluetoothHfpManager");
return;
}
signal = ceil(value.toNumber() / 20.0);
@ -600,7 +600,7 @@ BluetoothHfpManager::HandleVoiceConnectionChanged()
//
// Please see Bug 871366 for more information.
if (mOperatorName.Length() > 16) {
NS_WARNING("The operator name was longer than 16 characters. We cut it.");
BT_WARNING("The operator name was longer than 16 characters. We cut it.");
mOperatorName.Left(mOperatorName, 16);
}
}
@ -670,14 +670,14 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
ParseAtCommand(msg, 8, atCommandValues);
if (atCommandValues.Length() < 4) {
NS_WARNING("Could't get the value of command [AT+CMER=]");
BT_WARNING("Could't get the value of command [AT+CMER=]");
goto respond_with_ok;
}
if (!atCommandValues[0].EqualsLiteral("3") ||
!atCommandValues[1].EqualsLiteral("0") ||
!atCommandValues[2].EqualsLiteral("0")) {
NS_WARNING("Wrong value of CMER");
BT_WARNING("Wrong value of CMER");
goto respond_with_ok;
}
@ -686,7 +686,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
ParseAtCommand(msg, 8, atCommandValues);
if (atCommandValues.IsEmpty()) {
NS_WARNING("Could't get the value of command [AT+CMEE=]");
BT_WARNING("Could't get the value of command [AT+CMEE=]");
goto respond_with_ok;
}
@ -698,7 +698,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
ParseAtCommand(msg, 8, atCommandValues);
if (atCommandValues.Length() != 2) {
NS_WARNING("Could't get the value of command [AT+COPS=]");
BT_WARNING("Could't get the value of command [AT+COPS=]");
goto respond_with_ok;
}
@ -723,7 +723,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
ParseAtCommand(msg, 7, atCommandValues);
if (atCommandValues.Length() != 1) {
NS_WARNING("Couldn't get the value of command [AT+VTS=]");
BT_WARNING("Couldn't get the value of command [AT+VTS=]");
goto respond_with_ok;
}
@ -736,14 +736,14 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
ParseAtCommand(msg, 7, atCommandValues);
if (atCommandValues.IsEmpty()) {
NS_WARNING("Couldn't get the value of command [AT+VGM]");
BT_WARNING("Couldn't get the value of command [AT+VGM]");
goto respond_with_ok;
}
nsresult rv;
int vgm = atCommandValues[0].ToInteger(&rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to extract microphone volume from bluetooth headset!");
BT_WARNING("Failed to extract microphone volume from bluetooth headset!");
goto respond_with_ok;
}
@ -755,7 +755,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
ParseAtCommand(msg, 8, atCommandValues);
if (atCommandValues.IsEmpty()) {
NS_WARNING("Could't get the value of command [AT+CHLD=]");
BT_WARNING("Could't get the value of command [AT+CHLD=]");
goto respond_with_ok;
}
@ -776,10 +776,10 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
char chld = atCommandValues[0][0];
bool valid = true;
if (atCommandValues[0].Length() > 1) {
NS_WARNING("No index should be included in command [AT+CHLD]");
BT_WARNING("No index should be included in command [AT+CHLD]");
valid = false;
} else if (chld == '3' || chld == '4') {
NS_WARNING("The value of command [AT+CHLD] is not supported");
BT_WARNING("The value of command [AT+CHLD] is not supported");
valid = false;
} else if (chld == '0') {
// We need to rename these dialer commands for better readability
@ -791,7 +791,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
} else if (chld == '2') {
NotifyDialer(NS_LITERAL_STRING("CHLD=2"));
} else {
NS_WARNING("Wrong value of command [AT+CHLD]");
BT_WARNING("Wrong value of command [AT+CHLD]");
valid = false;
}
@ -805,14 +805,14 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
ParseAtCommand(msg, 7, atCommandValues);
if (atCommandValues.IsEmpty()) {
NS_WARNING("Could't get the value of command [AT+VGS=]");
BT_WARNING("Could't get the value of command [AT+VGS=]");
goto respond_with_ok;
}
nsresult rv;
int newVgs = atCommandValues[0].ToInteger(&rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to extract volume value from bluetooth headset!");
BT_WARNING("Failed to extract volume value from bluetooth headset!");
goto respond_with_ok;
}
@ -855,7 +855,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
nsAutoCString message(msg), newMsg;
int end = message.FindChar(';');
if (end < 0) {
NS_WARNING("Could't get the value of command [ATD]");
BT_WARNING("Could't get the value of command [ATD]");
goto respond_with_ok;
}
@ -865,7 +865,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
ParseAtCommand(msg, 8, atCommandValues);
if (atCommandValues.IsEmpty()) {
NS_WARNING("Could't get the value of command [AT+CLIP=]");
BT_WARNING("Could't get the value of command [AT+CLIP=]");
goto respond_with_ok;
}
@ -874,7 +874,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
ParseAtCommand(msg, 8, atCommandValues);
if (atCommandValues.IsEmpty()) {
NS_WARNING("Could't get the value of command [AT+CCWA=]");
BT_WARNING("Could't get the value of command [AT+CCWA=]");
goto respond_with_ok;
}
@ -907,7 +907,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
// (2) A SCO link exists
// (3) This is the very first AT+CKPD=200 of this session
// It is the case of Figure 4.3, Bluetooth HSP spec. Do nothing.
NS_WARNING("AT+CKPD=200: Do nothing");
BT_WARNING("AT+CKPD=200: Do nothing");
}
}
@ -956,7 +956,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
warningMsg.Append(NS_LITERAL_CSTRING("Unsupported AT command: "));
warningMsg.Append(msg);
warningMsg.Append(NS_LITERAL_CSTRING(", reply with ERROR"));
NS_WARNING(warningMsg.get());
BT_WARNING(warningMsg.get());
SendLine("ERROR");
return;
@ -1026,12 +1026,12 @@ BluetoothHfpManager::Listen()
MOZ_ASSERT(NS_IsMainThread());
if (sInShutdown) {
NS_WARNING("Listen called while in shutdown!");
BT_WARNING("Listen called while in shutdown!");
return false;
}
if (mSocket) {
NS_WARNING("mSocket exists. Failed to listen.");
BT_WARNING("mSocket exists. Failed to listen.");
return false;
}
@ -1041,7 +1041,7 @@ BluetoothHfpManager::Listen()
if (!mHandsfreeSocket->Listen(
BluetoothReservedChannels::CHANNEL_HANDSFREE_AG)) {
NS_WARNING("[HFP] Can't listen on RFCOMM socket!");
BT_WARNING("[HFP] Can't listen on RFCOMM socket!");
mHandsfreeSocket = nullptr;
return false;
}
@ -1053,7 +1053,7 @@ BluetoothHfpManager::Listen()
if (!mHeadsetSocket->Listen(
BluetoothReservedChannels::CHANNEL_HEADSET_AG)) {
NS_WARNING("[HSP] Can't listen on RFCOMM socket!");
BT_WARNING("[HSP] Can't listen on RFCOMM socket!");
mHandsfreeSocket->Disconnect();
mHandsfreeSocket = nullptr;
mHeadsetSocket = nullptr;
@ -1101,7 +1101,7 @@ bool
BluetoothHfpManager::SendCommand(const char* aCommand, uint32_t aValue)
{
if (!IsConnected()) {
NS_WARNING("Trying to SendCommand() without a SLC");
BT_WARNING("Trying to SendCommand() without a SLC");
return false;
}
@ -1115,7 +1115,7 @@ BluetoothHfpManager::SendCommand(const char* aCommand, uint32_t aValue)
}
if ((aValue < 1) || (aValue > ArrayLength(sCINDItems) - 1)) {
NS_WARNING("unexpected CINDType for CIEV command");
BT_WARNING("unexpected CINDType for CIEV command");
return false;
}
@ -1183,7 +1183,7 @@ BluetoothHfpManager::SendCommand(const char* aCommand, uint32_t aValue)
}
break;
default:
NS_WARNING("Not handling call status for CLCC");
BT_WARNING("Not handling call status for CLCC");
break;
}
message.AppendLiteral(",0,0,\"");
@ -1343,7 +1343,7 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
UpdateCIND(CINDType::CALLSETUP, CallSetupState::NO_CALLSETUP, aSend);
break;
default:
NS_WARNING("Not handling state changed");
BT_WARNING("Not handling state changed");
}
// = Handle callheld separately =
@ -1382,7 +1382,7 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
}
break;
default:
NS_WARNING("Not handling state changed");
BT_WARNING("Not handling state changed");
}
// Handle held calls separately
@ -1412,7 +1412,7 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
}
break;
default:
NS_WARNING("Not handling state changed");
BT_WARNING("Not handling state changed");
break;
}
}
@ -1621,12 +1621,12 @@ BluetoothHfpManager::ConnectSco(BluetoothReplyRunnable* aRunnable)
MOZ_ASSERT(NS_IsMainThread());
if (sInShutdown) {
NS_WARNING("ConnecteSco called while in shutdown!");
BT_WARNING("ConnecteSco called while in shutdown!");
return false;
}
if (!IsConnected()) {
NS_WARNING("BluetoothHfpManager is not connected");
BT_WARNING("BluetoothHfpManager is not connected");
return false;
}
@ -1634,7 +1634,7 @@ BluetoothHfpManager::ConnectSco(BluetoothReplyRunnable* aRunnable)
if (status == SocketConnectionStatus::SOCKET_CONNECTED ||
status == SocketConnectionStatus::SOCKET_CONNECTING ||
(mScoRunnable && (mScoRunnable != aRunnable))) {
NS_WARNING("SCO connection exists or is being established");
BT_WARNING("SCO connection exists or is being established");
return false;
}
@ -1654,13 +1654,13 @@ bool
BluetoothHfpManager::DisconnectSco()
{
if (!IsConnected()) {
NS_WARNING("BluetoothHfpManager is not connected");
BT_WARNING("BluetoothHfpManager is not connected");
return false;
}
SocketConnectionStatus status = mScoSocket->GetConnectionStatus();
if (status != SOCKET_CONNECTED && status != SOCKET_CONNECTING) {
NS_WARNING("No SCO exists");
BT_WARNING("No SCO exists");
return false;
}
@ -1674,20 +1674,20 @@ BluetoothHfpManager::ListenSco()
MOZ_ASSERT(NS_IsMainThread());
if (sInShutdown) {
NS_WARNING("ListenSco called while in shutdown!");
BT_WARNING("ListenSco called while in shutdown!");
return false;
}
if (mScoSocket->GetConnectionStatus() ==
SocketConnectionStatus::SOCKET_LISTENING) {
NS_WARNING("SCO socket has been already listening");
BT_WARNING("SCO socket has been already listening");
return false;
}
mScoSocket->Disconnect();
if (!mScoSocket->Listen(-1)) {
NS_WARNING("Can't listen on SCO socket!");
BT_WARNING("Can't listen on SCO socket!");
return false;
}

View File

@ -81,6 +81,11 @@ public:
virtual void OnConnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
virtual void OnDisconnect(const nsAString& AErrorStr) MOZ_OVERRIDE;
virtual void GetName(nsACString& aName)
{
aName.AssignLiteral("HFP/HSP");
}
bool Listen();
bool ConnectSco(BluetoothReplyRunnable* aRunnable = nullptr);
bool DisconnectSco();

View File

@ -236,7 +236,7 @@ BluetoothHidManager::NotifyStatusChanged()
BluetoothNamedValue(NS_LITERAL_STRING("address"), v));
if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to broadcast system message to settings");
BT_WARNING("Failed to broadcast system message to settings");
return;
}
}

View File

@ -37,6 +37,12 @@ public:
virtual void OnConnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
virtual void OnDisconnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
virtual void GetName(nsACString& aName)
{
aName.AssignLiteral("HID");
}
// HID-specific functions
void HandleInputPropertyChanged(const BluetoothSignal& aSignal);
private:

View File

@ -48,7 +48,7 @@ public:
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
NS_WARNING("Not a BluetoothNamedValue array!");
BT_WARNING("Not a BluetoothNamedValue array!");
SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
return false;
}
@ -61,7 +61,7 @@ public:
nsresult rv;
nsIScriptContext* sc = mManagerPtr->GetContextForEventHandlers(&rv);
if (!sc) {
NS_WARNING("Cannot create script context!");
BT_WARNING("Cannot create script context!");
SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
return false;
}
@ -71,7 +71,7 @@ public:
JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
rv = nsContentUtils::WrapNative(cx, global, adapter, aValue);
if (NS_FAILED(rv)) {
NS_WARNING("Cannot create native object!");
BT_WARNING("Cannot create native object!");
SetError(NS_LITERAL_STRING("BluetoothNativeObjectError"));
return false;
}
@ -120,7 +120,7 @@ BluetoothManager::SetPropertyByValue(const BluetoothNamedValue& aValue)
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling manager property: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(name));
NS_WARNING(warningMsg.get());
BT_WARNING(warningMsg.get());
#endif
}
@ -197,7 +197,7 @@ BluetoothManager::CheckPermission(nsPIDOMWindow* aWindow)
void
BluetoothManager::Notify(const BluetoothSignal& aData)
{
BT_LOG("[M] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
BT_LOGD("[M] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
if (aData.name().EqualsLiteral("AdapterAdded")) {
DispatchTrustedEvent(NS_LITERAL_STRING("adapteradded"));
@ -210,7 +210,7 @@ BluetoothManager::Notify(const BluetoothSignal& aData)
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling manager signal: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
NS_WARNING(warningMsg.get());
BT_WARNING(warningMsg.get());
#endif
}
}

View File

@ -113,7 +113,7 @@ public:
nsresult rv = mInputStream->Read(buf, mAvailablePacketSize, &numRead);
if (NS_FAILED(rv)) {
// Needs error handling here
NS_WARNING("Failed to read from input stream");
BT_WARNING("Failed to read from input stream");
return NS_ERROR_FAILURE;
}
@ -123,7 +123,7 @@ public:
nsRefPtr<SendSocketDataTask> task =
new SendSocketDataTask((uint8_t*)buf.forget(), numRead);
if (NS_FAILED(NS_DispatchToMainThread(task))) {
NS_WARNING("Failed to dispatch to main thread!");
BT_WARNING("Failed to dispatch to main thread!");
return NS_ERROR_FAILURE;
}
}
@ -308,7 +308,7 @@ BluetoothOppManager::Listen()
MOZ_ASSERT(NS_IsMainThread());
if (mSocket) {
NS_WARNING("mSocket exists. Failed to listen.");
BT_WARNING("mSocket exists. Failed to listen.");
return false;
}
@ -317,7 +317,7 @@ BluetoothOppManager::Listen()
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
if (!mRfcommSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH)) {
NS_WARNING("[OPP] Can't listen on RFCOMM socket!");
BT_WARNING("[OPP] Can't listen on RFCOMM socket!");
mRfcommSocket = nullptr;
return false;
}
@ -328,7 +328,7 @@ BluetoothOppManager::Listen()
new BluetoothSocket(this, BluetoothSocketType::EL2CAP, true, true);
if (!mL2capSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH_L2CAP)) {
NS_WARNING("[OPP] Can't listen on L2CAP socket!");
BT_WARNING("[OPP] Can't listen on L2CAP socket!");
mRfcommSocket->Disconnect();
mRfcommSocket = nullptr;
mL2capSocket = nullptr;
@ -450,7 +450,7 @@ BluetoothOppManager::AfterOppConnected()
if (!AcquireSdcardMountLock()) {
// If we fail to get a mount lock, abort this transaction
// Directly sending disconnect-request is better than abort-request
NS_WARNING("BluetoothOPPManager couldn't get a mount lock!");
BT_WARNING("BluetoothOPPManager couldn't get a mount lock!");
Disconnect(nullptr);
}
}
@ -580,7 +580,7 @@ BluetoothOppManager::ExtractBlobHeaders()
nsresult rv = mBlob->GetType(mContentType);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get content type");
BT_WARNING("Can't get content type");
SendDisconnectRequest();
return false;
}
@ -588,7 +588,7 @@ BluetoothOppManager::ExtractBlobHeaders()
uint64_t fileLength;
rv = mBlob->GetSize(&fileLength);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get file size");
BT_WARNING("Can't get file size");
SendDisconnectRequest();
return false;
}
@ -599,7 +599,7 @@ BluetoothOppManager::ExtractBlobHeaders()
// larger than UINT32_MAX, it needs to parse another OBEX Header
// and I would like to leave it as a feature.
if (fileLength > (uint64_t)UINT32_MAX) {
NS_WARNING("The file size is too large for now");
BT_WARNING("The file size is too large for now");
SendDisconnectRequest();
return false;
}
@ -607,7 +607,7 @@ BluetoothOppManager::ExtractBlobHeaders()
mFileLength = fileLength;
rv = NS_NewThread(getter_AddRefs(mReadFileThread));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create thread");
BT_WARNING("Can't create thread");
SendDisconnectRequest();
return false;
}
@ -829,10 +829,10 @@ BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
opCode == ObexRequestCode::GetFinal ||
opCode == ObexRequestCode::SetPath) {
ReplyError(ObexResponseCode::BadRequest);
NS_WARNING("Unsupported ObexRequestCode");
BT_WARNING("Unsupported ObexRequestCode");
} else {
ReplyError(ObexResponseCode::NotImplemented);
NS_WARNING("Unrecognized ObexRequestCode");
BT_WARNING("Unrecognized ObexRequestCode");
}
}
@ -878,7 +878,7 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
str += "[OPP] 0x";
str.AppendInt(mLastCommand, 16);
str += " failed";
NS_WARNING(str.get());
BT_WARNING(str.get());
FileTransferComplete();
return;
}
@ -942,7 +942,7 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
if (!mInputStream) {
rv = mBlob->GetInternalStream(getter_AddRefs(mInputStream));
if (NS_FAILED(rv)) {
NS_WARNING("Can't get internal stream of blob");
BT_WARNING("Can't get internal stream of blob");
SendDisconnectRequest();
return;
}
@ -952,11 +952,11 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
mRemoteMaxPacketLength);
rv = mReadFileThread->Dispatch(task, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
NS_WARNING("Cannot dispatch read file task!");
BT_WARNING("Cannot dispatch read file task!");
SendDisconnectRequest();
}
} else {
NS_WARNING("Unhandled ObexRequestCode");
BT_WARNING("Unhandled ObexRequestCode");
}
}
@ -1029,7 +1029,7 @@ BluetoothOppManager::SendPutRequest(uint8_t* aFileBody,
if (!mConnected) return;
if (aFileBodyLength > packetLeftSpace) {
NS_WARNING("Not allowed such a small MaxPacketLength value");
BT_WARNING("Not allowed such a small MaxPacketLength value");
return;
}
@ -1234,7 +1234,7 @@ BluetoothOppManager::FileTransferComplete()
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to broadcast [bluetooth-opp-transfer-complete]");
BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-complete]");
return;
}
@ -1270,7 +1270,7 @@ BluetoothOppManager::StartFileTransfer()
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to broadcast [bluetooth-opp-transfer-start]");
BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-start]");
return;
}
}
@ -1300,7 +1300,7 @@ BluetoothOppManager::UpdateProgress()
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to broadcast [bluetooth-opp-update-progress]");
BT_WARNING("Failed to broadcast [bluetooth-opp-update-progress]");
return;
}
}
@ -1330,7 +1330,7 @@ BluetoothOppManager::ReceivingFileConfirmation()
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to send [bluetooth-opp-receiving-file-confirmation]");
BT_WARNING("Failed to send [bluetooth-opp-receiving-file-confirmation]");
return;
}
}

View File

@ -78,6 +78,11 @@ public:
virtual void GetAddress(nsAString& aDeviceAddress) MOZ_OVERRIDE;
virtual bool IsConnected() MOZ_OVERRIDE;
virtual void GetName(nsACString& aName)
{
aName.AssignLiteral("OPP");
}
/*
* If an application wants to send a file, first, it needs to
* call Connect() to create a valid RFCOMM connection. After

View File

@ -17,6 +17,14 @@
USING_BLUETOOTH_NAMESPACE
#define BT_LOGR_PROFILE(mgr, args...) \
do { \
nsCString name; \
mgr->GetName(name); \
BT_LOGR("%s: [%s] %s", __FUNCTION__, name.get(), \
nsPrintfCString(args).get()); \
} while(0)
BluetoothProfileController::BluetoothProfileController(
const nsAString& aDeviceAddress,
BluetoothReplyRunnable* aRunnable,
@ -120,7 +128,6 @@ BluetoothProfileController::Connect(uint32_t aCod)
* It's almost impossible to send file to a remote device which is an Audio
* device or a Rendering device, so we won't connect OPP in that case.
*/
BluetoothProfileManagerBase* profile;
if (hasAudio) {
AddProfile(BluetoothHfpManager::Get());
}
@ -144,6 +151,7 @@ BluetoothProfileController::ConnectNext()
if (++mProfilesIndex < mProfiles.Length()) {
MOZ_ASSERT(!mDeviceAddress.IsEmpty());
BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
return;
@ -166,6 +174,8 @@ void
BluetoothProfileController::OnConnect(const nsAString& aErrorStr)
{
MOZ_ASSERT(NS_IsMainThread());
BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "<%s>",
NS_ConvertUTF16toUTF8(aErrorStr).get());
if (!aErrorStr.IsEmpty()) {
BT_WARNING(NS_ConvertUTF16toUTF8(aErrorStr).get());
@ -203,6 +213,8 @@ BluetoothProfileController::DisconnectNext()
MOZ_ASSERT(NS_IsMainThread());
if (++mProfilesIndex < mProfiles.Length()) {
BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
mProfiles[mProfilesIndex]->Disconnect(this);
return;
}
@ -224,6 +236,8 @@ void
BluetoothProfileController::OnDisconnect(const nsAString& aErrorStr)
{
MOZ_ASSERT(NS_IsMainThread());
BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "<%s>",
NS_ConvertUTF16toUTF8(aErrorStr).get());
if (!aErrorStr.IsEmpty()) {
BT_WARNING(NS_ConvertUTF16toUTF8(aErrorStr).get());
@ -233,4 +247,3 @@ BluetoothProfileController::OnDisconnect(const nsAString& aErrorStr)
DisconnectNext();
}

View File

@ -63,6 +63,11 @@ public:
*/
virtual void OnConnect(const nsAString& aErrorStr) = 0;
virtual void OnDisconnect(const nsAString& aErrorStr) = 0;
/**
* Returns string of profile name
*/
virtual void GetName(nsACString& aName) = 0;
};
END_BLUETOOTH_NAMESPACE

View File

@ -41,7 +41,7 @@ BluetoothPropertyContainer::SetProperty(nsIDOMWindow* aOwner,
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("Bluetooth service not available!");
BT_WARNING("Bluetooth service not available!");
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}

View File

@ -73,7 +73,7 @@ BluetoothReplyRunnable::Run()
}
if (NS_FAILED(rv)) {
NS_WARNING("Could not fire DOMRequest!");
BT_WARNING("Could not fire DOMRequest!");
}
ReleaseMembers();

View File

@ -192,10 +192,10 @@ TelephonyListener::NotifyError(int32_t aCallIndex,
hfp->HandleCallStateChanged(aCallIndex,
nsITelephonyProvider::CALL_STATE_DISCONNECTED,
aError, EmptyString(), false, true);
NS_WARNING("Reset the call state due to call transition ends abnormally");
BT_WARNING("Reset the call state due to call transition ends abnormally");
}
NS_WARNING(NS_ConvertUTF16toUTF8(aError).get());
BT_WARNING(NS_ConvertUTF16toUTF8(aError).get());
return NS_OK;
}

View File

@ -186,17 +186,17 @@ public:
* Please see bug 892392 for more information.
*/
if (!mIsStartup && mEnabled == gBluetoothService->IsEnabledInternal()) {
NS_WARNING("Bluetooth has already been enabled/disabled before.");
BT_WARNING("Bluetooth has already been enabled/disabled before.");
} else {
// Switch on/off bluetooth
if (mEnabled) {
if (NS_FAILED(gBluetoothService->StartInternal())) {
NS_WARNING("Bluetooth service failed to start!");
BT_WARNING("Bluetooth service failed to start!");
mEnabled = !mEnabled;
}
} else {
if (NS_FAILED(gBluetoothService->StopInternal())) {
NS_WARNING("Bluetooth service failed to stop!");
BT_WARNING("Bluetooth service failed to stop!");
mEnabled = !mEnabled;
}
}
@ -211,13 +211,13 @@ public:
// been toggled.
#if defined(MOZ_WIDGET_GONK)
if (property_set(PROP_BLUETOOTH_ENABLED, mEnabled ? "true" : "false") != 0) {
NS_WARNING("Failed to set bluetooth enabled property");
BT_WARNING("Failed to set bluetooth enabled property");
}
#endif
nsCOMPtr<nsIRunnable> ackTask = new BluetoothService::ToggleBtAck(mEnabled);
if (NS_FAILED(NS_DispatchToMainThread(ackTask))) {
NS_WARNING("Failed to dispatch to main thread!");
BT_WARNING("Failed to dispatch to main thread!");
}
return NS_OK;
@ -238,7 +238,7 @@ public:
MOZ_ASSERT(NS_IsMainThread());
if (!aResult.isBoolean()) {
NS_WARNING("Setting for '" BLUETOOTH_ENABLED_SETTING "' is not a boolean!");
BT_WARNING("Setting for '" BLUETOOTH_ENABLED_SETTING "' is not a boolean!");
return NS_OK;
}
@ -253,7 +253,7 @@ public:
NS_IMETHOD HandleError(const nsAString& aName)
{
NS_WARNING("Unable to get value for '" BLUETOOTH_ENABLED_SETTING "'");
BT_WARNING("Unable to get value for '" BLUETOOTH_ENABLED_SETTING "'");
return NS_OK;
}
};
@ -307,7 +307,7 @@ BluetoothService::Create()
#elif defined(MOZ_BLUETOOTH_DBUS)
return new BluetoothDBusService();
#endif
NS_WARNING("No platform support for bluetooth!");
BT_WARNING("No platform support for bluetooth!");
return nullptr;
}
@ -321,14 +321,14 @@ BluetoothService::Init()
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
false))) {
NS_WARNING("Failed to add shutdown observer!");
BT_WARNING("Failed to add shutdown observer!");
return false;
}
// Only the main process should observe bluetooth settings changes.
if (IsMainProcess() &&
NS_FAILED(obs->AddObserver(this, MOZSETTINGS_CHANGED_ID, false))) {
NS_WARNING("Failed to add settings change observer!");
BT_WARNING("Failed to add settings change observer!");
return false;
}
@ -344,7 +344,7 @@ BluetoothService::Cleanup()
if (obs &&
(NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
NS_FAILED(obs->RemoveObserver(this, MOZSETTINGS_CHANGED_ID)))) {
NS_WARNING("Can't unregister observers!");
BT_WARNING("Can't unregister observers!");
}
}
@ -356,7 +356,7 @@ BluetoothService::RegisterBluetoothSignalHandler(
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aHandler);
BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
BT_LOGD("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
BluetoothSignalObserverList* ol;
if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
@ -375,7 +375,7 @@ BluetoothService::UnregisterBluetoothSignalHandler(
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aHandler);
BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
BT_LOGD("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
BluetoothSignalObserverList* ol;
if (mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
@ -389,7 +389,7 @@ BluetoothService::UnregisterBluetoothSignalHandler(
}
}
else {
NS_WARNING("Node was never registered!");
BT_WARNING("Node was never registered!");
}
}
@ -434,7 +434,7 @@ BluetoothService::DistributeSignal(const BluetoothSignal& aSignal)
#if DEBUG
nsAutoCString msg("No observer registered for path ");
msg.Append(NS_ConvertUTF16toUTF8(aSignal.path()));
NS_WARNING(msg.get());
BT_WARNING(msg.get());
#endif
return;
}
@ -529,7 +529,7 @@ BluetoothService::SetEnabled(bool aEnabled)
* aEnabled: expected status of bluetooth
*/
if (mEnabled == aEnabled) {
NS_WARNING("Bluetooth has already been enabled/disabled before\
BT_WARNING("Bluetooth has already been enabled/disabled before\
or the toggling is failed.");
}
@ -735,7 +735,7 @@ BluetoothService::Get()
// If we're in shutdown, don't create a new instance
if (gInShutdown) {
NS_WARNING("BluetoothService can't be created during shutdown");
BT_WARNING("BluetoothService can't be created during shutdown");
return nullptr;
}
@ -784,11 +784,11 @@ BluetoothService::Notify(const BluetoothSignal& aData)
NS_ENSURE_TRUE_VOID(obj);
if (!SetJsObject(cx, aData.value(), obj)) {
NS_WARNING("Failed to set properties of system message!");
BT_WARNING("Failed to set properties of system message!");
return;
}
BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
BT_LOGD("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
if (aData.name().EqualsLiteral("RequestConfirmation")) {
MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 4,
@ -811,7 +811,7 @@ BluetoothService::Notify(const BluetoothSignal& aData)
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling service signal: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
NS_WARNING(warningMsg.get());
BT_WARNING(warningMsg.get());
return;
}

View File

@ -37,7 +37,7 @@ BluetoothSocket::Connect(const nsACString& aDeviceAddress, int aChannel)
if (!ConnectSocket(c.forget(), aDeviceAddress.BeginReading())) {
nsAutoString addr;
GetAddress(addr);
BT_LOG("%s failed. Current connected device address: %s",
BT_LOGD("%s failed. Current connected device address: %s",
__FUNCTION__, NS_ConvertUTF16toUTF8(addr).get());
return false;
}
@ -56,7 +56,7 @@ BluetoothSocket::Listen(int aChannel)
if (!ListenSocket(c.forget())) {
nsAutoString addr;
GetAddress(addr);
BT_LOG("%s failed. Current connected device address: %s",
BT_LOGD("%s failed. Current connected device address: %s",
__FUNCTION__, NS_ConvertUTF16toUTF8(addr).get());
return false;
}

View File

@ -99,13 +99,13 @@ BluetoothUnixSocketConnector::SetUp(int aFd)
if (lm) {
if (mType == BluetoothSocketType::RFCOMM) {
if (setsockopt(aFd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
NS_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
BT_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
return false;
}
} else if (mType == BluetoothSocketType::L2CAP ||
mType == BluetoothSocketType::EL2CAP) {
if (setsockopt(aFd, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm))) {
NS_WARNING("setsockopt(L2CAP_LM) failed, throwing");
BT_WARNING("setsockopt(L2CAP_LM) failed, throwing");
return false;
}
}
@ -114,7 +114,7 @@ BluetoothUnixSocketConnector::SetUp(int aFd)
if (mType == BluetoothSocketType::RFCOMM) {
sndbuf = RFCOMM_SO_SNDBUF;
if (setsockopt(aFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
NS_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
BT_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
return false;
}
}
@ -146,13 +146,13 @@ BluetoothUnixSocketConnector::SetUp(int aFd)
if (mType == BluetoothSocketType::EL2CAP) {
sndbuf = L2CAP_SO_SNDBUF;
if (setsockopt(aFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
NS_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
BT_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
return false;
}
rcvbuf = L2CAP_SO_RCVBUF;
if (setsockopt(aFd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) {
NS_WARNING("setsockopt(SO_RCVBUF) failed, throwing");
BT_WARNING("setsockopt(SO_RCVBUF) failed, throwing");
return false;
}
}
@ -185,12 +185,12 @@ BluetoothUnixSocketConnector::Create()
}
if (fd < 0) {
NS_WARNING("Could not open bluetooth socket!");
BT_WARNING("Could not open bluetooth socket!");
return -1;
}
if (!SetUp(fd)) {
NS_WARNING("Could not set up socket!");
BT_WARNING("Could not set up socket!");
return -1;
}
@ -208,7 +208,7 @@ BluetoothUnixSocketConnector::CreateAddr(bool aIsServer,
if (!aIsServer && aAddress && strlen(aAddress) > 0) {
if (get_bdaddr(aAddress, &bd_address_obj)) {
NS_WARNING("Can't get bluetooth address!");
BT_WARNING("Can't get bluetooth address!");
return false;
}
}
@ -239,7 +239,7 @@ BluetoothUnixSocketConnector::CreateAddr(bool aIsServer,
memcpy(&aAddr.sco.sco_bdaddr, &bd_address_obj, sizeof(bd_address_obj));
break;
default:
NS_WARNING("Socket type unknown!");
BT_WARNING("Socket type unknown!");
return false;
}
return true;

View File

@ -29,7 +29,7 @@ SetJsObject(JSContext* aContext,
MOZ_ASSERT(aContext && aObj);
if (aValue.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
NS_WARNING("SetJsObject: Invalid parameter type");
BT_WARNING("SetJsObject: Invalid parameter type");
return false;
}
@ -56,14 +56,14 @@ SetJsObject(JSContext* aContext,
val = BOOLEAN_TO_JSVAL(v.get_bool());
break;
default:
NS_WARNING("SetJsObject: Parameter is not handled");
BT_WARNING("SetJsObject: Parameter is not handled");
break;
}
if (!JS_SetProperty(aContext, aObj,
NS_ConvertUTF16toUTF8(arr[i].name()).get(),
val)) {
NS_WARNING("Failed to set property");
BT_WARNING("Failed to set property");
return false;
}
}
@ -112,12 +112,12 @@ BroadcastSystemMessage(const nsAString& aType,
JS::RootedObject obj(cx, JS_NewObject(cx, NULL, NULL, NULL));
if (!obj) {
NS_WARNING("Failed to new JSObject for system message!");
BT_WARNING("Failed to new JSObject for system message!");
return false;
}
if (!SetJsObject(cx, aData, obj)) {
NS_WARNING("Failed to set properties of system message!");
BT_WARNING("Failed to set properties of system message!");
return false;
}
@ -149,7 +149,7 @@ DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable,
aRunnable->SetReply(reply);
if (NS_FAILED(NS_DispatchToMainThread(aRunnable))) {
NS_WARNING("Failed to dispatch to main thread!");
BT_WARNING("Failed to dispatch to main thread!");
}
}

View File

@ -99,10 +99,11 @@ StartStopGonkBluetooth(bool aShouldEnable)
// if isEnabled < 0, this means we brought up the firmware, but something
// went wrong with bluetoothd. Post a warning message, but try to proceed
// with firmware unloading if that was requested, so we can retry later.
NS_WARNING("Bluetooth firmware up, but cannot connect to HCI socket! Check bluetoothd and try stopping/starting bluetooth again.");
BT_WARNING("Bluetooth firmware up, but cannot connect to HCI socket! "
"Check bluetoothd and try stopping/starting bluetooth again.");
// Just disable now, return an error.
if (sBluedroidFunctions.bt_disable() != 0) {
NS_WARNING("Problem shutting down bluetooth after error in bringup!");
BT_WARNING("Problem shutting down bluetooth after error in bringup!");
}
return NS_ERROR_FAILURE;
}
@ -110,7 +111,7 @@ StartStopGonkBluetooth(bool aShouldEnable)
result = (sBluedroidFunctions.bt_disable() == 0) ? true : false;
}
if (!result) {
NS_WARNING("Could not set gonk bluetooth firmware!");
BT_WARNING("Could not set gonk bluetooth firmware!");
return NS_ERROR_FAILURE;
}

View File

@ -48,7 +48,7 @@ public:
mRequest->RequestComplete();
if (!mRequest->Send__delete__(mRequest, *mReply)) {
NS_WARNING("Failed to send response to child process!");
BT_WARNING("Failed to send response to child process!");
return NS_ERROR_FAILURE;
}
}

View File

@ -35,7 +35,6 @@
#include "nsThreadUtils.h"
#include "nsDebug.h"
#include "nsDataHashtable.h"
#include "nsPrintfCString.h"
#include "mozilla/Atomics.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/Hal.h"
@ -170,7 +169,6 @@ static const char* sBluetoothDBusSignals[] =
/**
* DBus Connection held for the BluetoothCommandThread to use. Should never be
* used by any other thread.
*
*/
static nsRefPtr<RawDBusConnection> gThreadConnection;
static nsDataHashtable<nsStringHashKey, DBusMessage* >* sPairingReqTable;
@ -206,7 +204,7 @@ GetPairedDevicesFilter(const BluetoothValue& aValue)
{
// Check property 'Paired' and only paired device will be returned
if (aValue.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
NS_WARNING("Not a BluetoothNamedValue array!");
BT_WARNING("Not a BluetoothNamedValue array!");
return false;
}
@ -368,30 +366,6 @@ IsDBusMessageError(DBusMessage* aMsg, DBusError* aErr, nsAString& aErrorStr)
return false;
}
static void
UnpackIntMessage(DBusMessage* aMsg, DBusError* aErr,
BluetoothValue& aValue, nsAString& aErrorStr)
{
MOZ_ASSERT(aMsg);
DBusError err;
dbus_error_init(&err);
if (!IsDBusMessageError(aMsg, aErr, aErrorStr)) {
MOZ_ASSERT(dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN,
"Got dbus callback that's not a METHOD_RETURN!");
int i;
if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_INT32,
&i, DBUS_TYPE_INVALID)) {
if (dbus_error_is_set(&err)) {
aErrorStr = NS_ConvertUTF8toUTF16(err.message);
LOG_AND_FREE_DBUS_ERROR(&err);
}
} else {
aValue = (uint32_t)i;
}
}
}
static void
UnpackObjectPathMessage(DBusMessage* aMsg, DBusError* aErr,
BluetoothValue& aValue, nsAString& aErrorStr)
@ -422,13 +396,13 @@ public:
{
BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
if (!hfp || !hfp->Listen()) {
NS_WARNING("Failed to start listening for BluetoothHfpManager!");
BT_WARNING("Failed to start listening for BluetoothHfpManager!");
return NS_ERROR_FAILURE;
}
BluetoothOppManager* opp = BluetoothOppManager::Get();
if (!opp || !opp->Listen()) {
NS_WARNING("Failed to start listening for BluetoothOppManager!");
BT_WARNING("Failed to start listening for BluetoothOppManager!");
return NS_ERROR_FAILURE;
}
@ -651,9 +625,9 @@ GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
}
if ((receivedType != expectedType) && !convert) {
NS_WARNING(nsPrintfCString("Iterator not type we expect! Property name: %s,
Property Type Expected: %d, Property Type Received: %d",
NS_ConvertUTF16toUTF8(propertyName).get(), expectedType, receivedType).get());
BT_WARNING("Iterator not type we expect! Property name: %s,"
"Property Type Expected: %d, Property Type Received: %d",
NS_ConvertUTF16toUTF8(propertyName).get(), expectedType, receivedType);
return false;
}
@ -742,7 +716,7 @@ ParseProperties(DBusMessageIter* aIter,
if (!GetProperty(dict_entry, aPropertyTypes, aPropertyTypeLen, &prop_index,
props)) {
aErrorStr.AssignLiteral("Can't Create Property!");
NS_WARNING("Can't create property!");
BT_WARNING("Can't create property!");
return;
}
} while (dbus_message_iter_next(&dict));
@ -802,13 +776,13 @@ ParsePropertyChange(DBusMessage* aMsg, BluetoothValue& aValue,
dbus_error_init(&err);
if (!dbus_message_iter_init(aMsg, &iter)) {
NS_WARNING("Can't create iterator!");
BT_WARNING("Can't create iterator!");
return;
}
if (!GetProperty(iter, aPropertyTypes, aPropertyTypeLen,
&prop_index, props)) {
NS_WARNING("Can't get property!");
BT_WARNING("Can't get property!");
aErrorStr.AssignLiteral("Can't get property!");
return;
}
@ -939,7 +913,7 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
DBusError err;
dbus_error_init(&err);
BT_LOG("%s: %s, %s", __FUNCTION__,
BT_LOGD("%s: %s, %s", __FUNCTION__,
dbus_message_get_path(msg),
dbus_message_get_member(msg));
@ -991,7 +965,7 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
goto handle_error;
}
DBusMessage* reply;
DBusMessage* reply = nullptr;
int i;
int length = sAuthorizedServiceClass.Length();
for (i = 0; i < length; i++) {
@ -1199,7 +1173,7 @@ public:
ExtractHandles(aReply, handles);
if(!RegisterAgent(&sAgentVTable)) {
NS_WARNING("Failed to register agent");
BT_WARNING("Failed to register agent");
}
}
@ -1380,7 +1354,7 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
nsAutoString signalName;
nsAutoString signalInterface;
BT_LOG("%s: %s, %s, %s", __FUNCTION__,
BT_LOGD("%s: %s, %s, %s", __FUNCTION__,
dbus_message_get_interface(aMsg),
dbus_message_get_path(aMsg),
dbus_message_get_member(aMsg));
@ -1406,7 +1380,7 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
DBusMessageIter iter;
if (!dbus_message_iter_init(aMsg, &iter)) {
NS_WARNING("Can't create iterator!");
BT_WARNING("Can't create iterator!");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@ -1583,7 +1557,7 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
}
if (!errorStr.IsEmpty()) {
NS_WARNING(NS_ConvertUTF16toUTF8(errorStr).get());
BT_WARNING(NS_ConvertUTF16toUTF8(errorStr).get());
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@ -1633,7 +1607,7 @@ bool
BluetoothDBusService::IsReady()
{
if (!IsEnabled() || !mConnection || !gThreadConnection || IsToggling()) {
NS_WARNING("Bluetooth service is not ready yet!");
BT_WARNING("Bluetooth service is not ready yet!");
return false;
}
return true;
@ -1646,7 +1620,7 @@ BluetoothDBusService::StartInternal()
MOZ_ASSERT(!NS_IsMainThread());
if (!StartDBus()) {
NS_WARNING("Cannot start DBus thread!");
BT_WARNING("Cannot start DBus thread!");
return NS_ERROR_FAILURE;
}
@ -1655,7 +1629,7 @@ BluetoothDBusService::StartInternal()
}
if (NS_FAILED(EstablishDBusConnection())) {
NS_WARNING("Cannot start Main Thread DBus connection!");
BT_WARNING("Cannot start Main Thread DBus connection!");
StopDBus();
return NS_ERROR_FAILURE;
}
@ -1663,7 +1637,7 @@ BluetoothDBusService::StartInternal()
gThreadConnection = new RawDBusConnection();
if (NS_FAILED(gThreadConnection->EstablishDBusConnection())) {
NS_WARNING("Cannot start Sync Thread DBus connection!");
BT_WARNING("Cannot start Sync Thread DBus connection!");
StopDBus();
return NS_ERROR_FAILURE;
}
@ -1687,7 +1661,7 @@ BluetoothDBusService::StartInternal()
// Add a filter for all incoming messages_base
if (!dbus_connection_add_filter(mConnection, EventFilter,
NULL, NULL)) {
NS_WARNING("Cannot create DBus Event Filter for DBus Thread!");
BT_WARNING("Cannot create DBus Event Filter for DBus Thread!");
return NS_ERROR_FAILURE;
}
@ -1704,7 +1678,7 @@ BluetoothDBusService::StartInternal()
// Adapter path has been ready. let's do PrepareAdapterRunnable now
nsRefPtr<PrepareAdapterRunnable> b = new PrepareAdapterRunnable(v.get_nsString());
if (NS_FAILED(NS_DispatchToMainThread(b))) {
NS_WARNING("Failed to dispatch to main thread!");
BT_WARNING("Failed to dispatch to main thread!");
}
}
@ -2276,7 +2250,7 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType,
"SetProperty");
if (!msg) {
NS_WARNING("Could not allocate D-Bus message object!");
BT_WARNING("Could not allocate D-Bus message object!");
return NS_ERROR_FAILURE;
}
@ -2284,7 +2258,7 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType,
const char* propName = intermediatePropName.get();
if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &propName,
DBUS_TYPE_INVALID)) {
NS_WARNING("Couldn't append arguments to dbus message!");
BT_WARNING("Couldn't append arguments to dbus message!");
return NS_ERROR_FAILURE;
}
@ -2306,7 +2280,7 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType,
val = &(tmp_int);
type = DBUS_TYPE_BOOLEAN;
} else {
NS_WARNING("Property type not handled!");
BT_WARNING("Property type not handled!");
dbus_message_unref(msg);
return NS_ERROR_FAILURE;
}
@ -2318,7 +2292,7 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType,
var_type, &value_iter) ||
!dbus_message_iter_append_basic(&value_iter, type, val) ||
!dbus_message_iter_close_container(&iter, &value_iter)) {
NS_WARNING("Could not append argument to method call!");
BT_WARNING("Could not append argument to method call!");
dbus_message_unref(msg);
return NS_ERROR_FAILURE;
}
@ -2331,7 +2305,7 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType,
1000,
GetVoidCallback,
(void*)aRunnable)) {
NS_WARNING("Could not start async function!");
BT_WARNING("Could not start async function!");
return NS_ERROR_FAILURE;
}
runnable.forget();
@ -2413,7 +2387,7 @@ BluetoothDBusService::CreatePairedDeviceInternal(
DBUS_TYPE_STRING, &capabilities,
DBUS_TYPE_INVALID);
if (!ret) {
NS_WARNING("Could not start async function!");
BT_WARNING("Could not start async function!");
return NS_ERROR_FAILURE;
}
@ -2677,7 +2651,7 @@ BluetoothDBusService::IsConnected(const uint16_t aServiceUuid)
BluetoothProfileManagerBase* profile =
BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid);
if (!profile) {
NS_WARNING(ERR_UNKNOWN_PROFILE);
BT_WARNING(ERR_UNKNOWN_PROFILE);
return false;
}

View File

@ -4,8 +4,8 @@
* 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_bluetoothdbuseventservice_h__
#define mozilla_dom_bluetooth_bluetoothdbuseventservice_h__
#ifndef mozilla_dom_bluetooth_bluetoothdbusservice_h__
#define mozilla_dom_bluetooth_bluetoothdbusservice_h__
#include "mozilla/Attributes.h"
#include "BluetoothCommon.h"

View File

@ -812,12 +812,12 @@ add_test(function test_PduHelper_parseHeaders() {
// Parse ends with Content-Type
let expect = {};
expect["x-mms-mms-version"] = MMS_VERSION;
expect["x-mms-mms-version"] = MMS_VERSION_1_3;
expect["content-type"] = {
media: "application/vnd.wap.multipart.related",
params: null,
};
parse([0x80 | 0x0D, 0x80 | MMS_VERSION, // X-Mms-Mms-Version: 1.3
parse([0x80 | 0x0D, 0x80 | MMS_VERSION_1_3, // X-Mms-Mms-Version: 1.3
0x80 | 0x04, 0x80 | 0x33, // Content-Type: application/vnd.wap.multipart.related
0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ // X-Mms-Message-Type: M-Send.req
], expect);
@ -904,7 +904,7 @@ add_test(function test_PduHelper_encodeHeaders() {
let headers = {};
headers["x-mms-message-type"] = MMS_PDU_TYPE_SEND_REQ;
headers["x-mms-mms-version"] = MMS_VERSION;
headers["x-mms-mms-version"] = MMS_VERSION_1_3;
headers["x-mms-transaction-id"] = "asdf";
headers["to"] = { address: "+123", type: "PLMN" };
headers["content-type"] = {
@ -913,7 +913,7 @@ add_test(function test_PduHelper_encodeHeaders() {
wsp_encode_test_ex(func, headers,
Array.concat([0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ])
.concat([0x80 | 0x18]).concat(strToCharCodeArray(headers["x-mms-transaction-id"]))
.concat([0x80 | 0x0D, 0x80 | MMS_VERSION])
.concat([0x80 | 0x0D, 0x80 | MMS_VERSION_1_3])
.concat([0x80 | 0x17]).concat(strToCharCodeArray("+123/TYPE=PLMN"))
.concat([0x80 | 0x04, 0x80 | 0x33]));

View File

@ -345,7 +345,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
// already forgotten its permissions so we need to unregister the target
// for every permission.
this._unregisterMessageTarget(null, msg.target);
return;
return null;
}
if (RIL_IPC_MOBILECONNECTION_MSG_NAMES.indexOf(msg.name) != -1) {
@ -388,16 +388,16 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
switch (msg.name) {
case "RIL:RegisterMobileConnectionMsg":
this._registerMessageTarget("mobileconnection", msg.target);
return;
return null;
case "RIL:RegisterIccMsg":
this._registerMessageTarget("icc", msg.target);
return;
return null;
case "RIL:RegisterVoicemailMsg":
this._registerMessageTarget("voicemail", msg.target);
return;
return null;
case "RIL:RegisterCellBroadcastMsg":
this._registerMessageTarget("cellbroadcast", msg.target);
return;
return null;
}
let clientId = msg.json.clientId || 0;
@ -914,6 +914,7 @@ RadioInterface.prototype = {
this.workerMessenger.sendWithIPCMessage(msg, "queryVoicePrivacyMode");
break;
}
return null;
},
handleUnsolicitedWorkerMessage: function handleUnsolicitedWorkerMessage(message) {

View File

@ -53,13 +53,6 @@ if (!this.debug) {
};
}
const INT32_MAX = 2147483647;
const UINT8_SIZE = 1;
const UINT16_SIZE = 2;
const UINT32_SIZE = 4;
const PDU_HEX_OCTET_SIZE = 4;
const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
// Timeout value for emergency callback mode.
@ -150,7 +143,7 @@ let Buf = {
return;
}
RIL.handleParcel(request_type, this.mReadAvailable, options);
RIL.handleParcel(request_type, this.readAvailable, options);
},
/**
@ -166,7 +159,7 @@ let Buf = {
if (DEBUG) debug("New outgoing parcel of type " + type);
// We're going to leave room for the parcel size at the beginning.
this.mOutgoingIndex = this.PARCEL_SIZE_SIZE;
this.outgoingIndex = this.PARCEL_SIZE_SIZE;
this.writeUint32(type);
this.writeUint32(this.mToken);
@ -3976,7 +3969,7 @@ let RIL = {
Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, options);
Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable()
- 2 * UINT32_SIZE)); // Skip response_type & request_type.
- 2 * Buf.UINT32_SIZE)); // Skip response_type & request_type.
let messageStringLength = Buf.readUint32(); // In semi-octets
let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA
let tpduLength = (messageStringLength / 2) - (smscLength + 1); // In octets
@ -4009,7 +4002,7 @@ let RIL = {
if (smscLength) {
GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ADDRESS);
GsmPDUHelper.writeHexOctet(smscLength);
Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * smscLength);
Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * smscLength);
}
// SMS TPDU-TLV
@ -4019,7 +4012,7 @@ let RIL = {
GsmPDUHelper.writeHexOctet(0x81);
}
GsmPDUHelper.writeHexOctet(tpduLength);
Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * tpduLength);
Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * tpduLength);
// Write 2 string delimitors for the total string length must be even.
Buf.writeStringDelimiter(0);
@ -4068,7 +4061,7 @@ let RIL = {
GsmPDUHelper.writeHexOctet(responsePduLen);
}
// TP-UD
Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * responsePduLen);
Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * responsePduLen);
// Write 2 string delimitors for the total string length must be even.
Buf.writeStringDelimiter(0);
@ -4085,19 +4078,19 @@ let RIL = {
Buf.writeUint32(EFSMS_STATUS_FREE);
Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable()
- 2 * UINT32_SIZE)); // Skip response_type & request_type.
- 2 * Buf.UINT32_SIZE)); // Skip response_type & request_type.
let messageStringLength = Buf.readUint32(); // In semi-octets
let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA
let pduLength = (messageStringLength / 2) - (smscLength + 1); // In octets
// 1. Write PDU first.
if (smscLength > 0) {
Buf.seekIncoming(smscLength * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(smscLength * Buf.PDU_HEX_OCTET_SIZE);
}
// Write EFsms PDU string length
Buf.writeUint32(2 * pduLength); // In semi-octets
if (pduLength) {
Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * pduLength);
Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * pduLength);
}
// Write 2 string delimitors for the total string length must be even.
Buf.writeStringDelimiter(0);
@ -4110,9 +4103,9 @@ let RIL = {
// Write TOA & SMSC Address
if (smscLength) {
Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable()
- 2 * UINT32_SIZE // Skip response_type, request_type.
- 2 * PDU_HEX_OCTET_SIZE)); // Skip messageStringLength & smscLength.
Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * smscLength);
- 2 * Buf.UINT32_SIZE // Skip response_type, request_type.
- 2 * Buf.PDU_HEX_OCTET_SIZE)); // Skip messageStringLength & smscLength.
Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * smscLength);
}
// Write 2 string delimitors for the total string length must be even.
Buf.writeStringDelimiter(0);
@ -4129,7 +4122,8 @@ let RIL = {
* @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22.
*/
_processSmsMultipart: function _processSmsMultipart(message) {
if (message.header && (message.header.segmentMaxSeq > 1)) {
if (message.header && message.header.segmentMaxSeq &&
(message.header.segmentMaxSeq > 1)) {
message = this._processReceivedSmsSegment(message);
} else {
if (message.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
@ -6583,7 +6577,7 @@ let GsmPDUHelper = {
}
}
Buf.seekIncoming((numOctets - i) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE);
return ret;
},
@ -6695,7 +6689,7 @@ let GsmPDUHelper = {
}
// Skip trailing 0xff
Buf.seekIncoming((numOctets - i) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE);
break;
case 0x81: // Fall through
case 0x82:
@ -6749,14 +6743,14 @@ let GsmPDUHelper = {
}
// Unread.
// +1 for the GSM alphabet indexed at i,
Buf.seekIncoming(-1 * (count + 1) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(-1 * (count + 1) * Buf.PDU_HEX_OCTET_SIZE);
str += this.read8BitUnpackedToString(count + 1 - gotUCS2);
i += count - gotUCS2;
}
}
// Skipping trailing 0xff
Buf.seekIncoming((numOctets - len - headerLen) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming((numOctets - len - headerLen) * Buf.PDU_HEX_OCTET_SIZE);
break;
}
return str;
@ -7026,7 +7020,7 @@ let GsmPDUHelper = {
let number = this.readNumberWithLength();
// Skip 2 unused octets, CCP and EXT1.
Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
Buf.readStringDelimiter(length);
let contact = null;
@ -7088,7 +7082,7 @@ let GsmPDUHelper = {
numOctets--;
return this.readICCUCS2String(temp, numOctets);
} else {
Buf.seekIncoming(-1 * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(-1 * Buf.PDU_HEX_OCTET_SIZE);
return this.read8BitUnpackedToString(numOctets);
}
},
@ -7192,9 +7186,9 @@ let GsmPDUHelper = {
}
number = this.readDiallingNumber(numLen);
Buf.seekIncoming((ADN_MAX_BCD_NUMBER_BYTES - numLen) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming((ADN_MAX_BCD_NUMBER_BYTES - numLen) * Buf.PDU_HEX_OCTET_SIZE);
} else {
Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE);
}
return number;
@ -9860,7 +9854,7 @@ let StkProactiveCmdHelper = {
if (DEBUG) {
debug("Unknown comprehension tag " + tag.toString(16));
}
Buf.seekIncoming(length * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(length * Buf.PDU_HEX_OCTET_SIZE);
return null;
}
return method.call(this, length);
@ -10826,7 +10820,7 @@ let ICCIOHelper = {
// The format is from TS 51.011, clause 9.2.1
// Skip RFU, data[0] data[1]
Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
// File size, data[2], data[3]
options.fileSize = (GsmPDUHelper.readHexOctet() << 8) |
@ -10851,7 +10845,7 @@ let ICCIOHelper = {
// 1 byte File status, data[11],
// 1 byte Length of the following data, data[12].
Buf.seekIncoming(((RESPONSE_DATA_STRUCTURE - RESPONSE_DATA_FILE_TYPE - 1) *
PDU_HEX_OCTET_SIZE));
Buf.PDU_HEX_OCTET_SIZE));
// Read Structure of EF, data[13]
let efType = GsmPDUHelper.readHexOctet();
@ -10865,7 +10859,7 @@ let ICCIOHelper = {
options.recordSize = GsmPDUHelper.readHexOctet();
options.totalRecords = options.fileSize / options.recordSize;
} else {
Buf.seekIncoming(1 * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE);
}
Buf.readStringDelimiter(strLen);
@ -11258,7 +11252,7 @@ let ICCRecordHelper = {
let tag = GsmPDUHelper.readHexOctet();
if (tag == 0xff) {
readLen++;
Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
break;
}
@ -11402,7 +11396,7 @@ let ICCRecordHelper = {
email = GsmPDUHelper.read8BitUnpackedToString(octetLen - 2);
// Consumes the remaining buffer
Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE); // For ADN SFI and Record Identifier
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); // For ADN SFI and Record Identifier
}
Buf.readStringDelimiter(strLen);
@ -11480,17 +11474,17 @@ let ICCRecordHelper = {
this._anrRecordSize = options.recordSize;
// Skip EF_AAS Record ID.
Buf.seekIncoming(1 * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE);
number = GsmPDUHelper.readNumberWithLength();
// Skip 2 unused octets, CCP and EXT1.
Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
// For Type 2 there are two extra octets.
if (fileType == ICC_USIM_TYPE2_TAG) {
// Skip 2 unused octets, ADN SFI and Record Identifier.
Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
}
Buf.readStringDelimiter(strLen);
@ -11587,7 +11581,7 @@ let ICCRecordHelper = {
}
// Consume unread octets.
Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
Buf.readStringDelimiter(strLen);
if (DEBUG) debug("SPDI: " + JSON.stringify(RIL.iccInfoPrivate.SPDI));
@ -11763,7 +11757,7 @@ let ICCRecordHelper = {
}
opl.push(oplElement);
} else {
Buf.seekIncoming(5 * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(5 * Buf.PDU_HEX_OCTET_SIZE);
}
Buf.readStringDelimiter(strLen);
@ -11797,7 +11791,7 @@ let ICCRecordHelper = {
if (tlvTag == 0xFF) {
// Unused byte
readLen++;
Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
break;
}
@ -11814,7 +11808,7 @@ let ICCRecordHelper = {
pnnElement.shortName = GsmPDUHelper.readNetworkName(tlvLen);
break;
default:
Buf.seekIncoming(tlvLen * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(tlvLen * Buf.PDU_HEX_OCTET_SIZE);
break;
}
@ -11872,7 +11866,7 @@ let ICCRecordHelper = {
}
return;
} else {
Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
}
Buf.readStringDelimiter(strLen);
@ -12925,7 +12919,7 @@ let RuimRecordHelper = {
cdmaHomeNetworkId.push(((GsmPDUHelper.readHexOctet() & 0xff) << 8) | tempOctet);
// Consuming the last octet: band class.
Buf.seekIncoming(PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE);
Buf.readStringDelimiter(strLen);
if (options.p1 < options.totalRecords) {
@ -12982,7 +12976,7 @@ let RuimRecordHelper = {
let displayCondition = GsmPDUHelper.readHexOctet();
let codingScheme = GsmPDUHelper.readHexOctet();
// Skip one octet: language indicator.
Buf.seekIncoming(PDU_HEX_OCTET_SIZE);
Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE);
let readLen = 3;
// SPN String ends up with 0xff.
@ -13018,7 +13012,7 @@ let RuimRecordHelper = {
", Display condition: " + displayCondition);
}
RIL.iccInfoPrivate.spnDisplayCondition = displayCondition;
Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
Buf.readStringDelimiter(strLen);
}

View File

@ -25,7 +25,10 @@ function newWorker(custom_ns) {
let worker_ns = {
importScripts: function fakeImportScripts() {
Array.slice(arguments).forEach(function (script) {
subscriptLoader.loadSubScript("resource://gre/modules/" + script, this);
if (!script.startsWith("resource:")) {
script = "resource://gre/modules/" + script;
}
subscriptLoader.loadSubScript(script, this);
}, this);
},
@ -54,6 +57,22 @@ function newWorker(custom_ns) {
worker_ns[key] = custom_ns[key];
}
// fake require() for toolkit/components/workerloader/require.js
let require = (function() {
return function require(script) {
worker_ns.module = {};
worker_ns.importScripts(script);
return worker_ns;
}
})();
Object.freeze(require);
Object.defineProperty(worker_ns, "require", {
value: require,
enumerable: true,
configurable: false
});
// Load the RIL worker itself.
worker_ns.importScripts("ril_worker.js");
@ -123,15 +142,16 @@ function newIncomingParcel(fakeParcelSize, response, request, data) {
/**
*
*/
function newRadioInterfaceLayer() {
let ril_ns = {
ChromeWorker: function ChromeWorker() {
// Stub function
},
};
let ril_ns;
function newRadioInterface() {
if (!ril_ns) {
ril_ns = {};
subscriptLoader.loadSubScript("resource://gre/components/RadioInterfaceLayer.js", ril_ns);
}
subscriptLoader.loadSubScript("resource://gre/components/RadioInterfaceLayer.js", ril_ns);
return new ril_ns.RadioInterfaceLayer();
return {
__proto__: ril_ns.RadioInterface.prototype,
};
}
/**

View File

@ -32,7 +32,8 @@ function add_test_incoming_parcel(parcel, handler) {
}
// supports only requests less or equal than UINT8_MAX(255).
let request = parcel[worker.PARCEL_SIZE_SIZE + worker.UINT32_SIZE];
let buf = worker.Buf;
let request = parcel[buf.PARCEL_SIZE_SIZE + buf.UINT32_SIZE];
worker.RIL[request] = function ril_request_handler() {
handler(worker);
worker.postMessage();
@ -111,19 +112,19 @@ add_test(function test_incoming_parcel_buffer_overwritten() {
// Prepare two parcels, whose sizes are both smaller than the incoming buffer
// size but larger when combined, to trigger the bug.
let pA_dataLength = buf.INCOMING_BUFFER_LENGTH / 2;
let pA_dataLength = buf.incomingBufferLength / 2;
let pA = newIncomingParcel(-1,
worker.RESPONSE_TYPE_UNSOLICITED,
request,
calloc(pA_dataLength, 1));
let pA_parcelSize = pA.length - worker.PARCEL_SIZE_SIZE;
let pA_parcelSize = pA.length - buf.PARCEL_SIZE_SIZE;
let pB_dataLength = buf.INCOMING_BUFFER_LENGTH * 3 / 4;
let pB_dataLength = buf.incomingBufferLength * 3 / 4;
let pB = newIncomingParcel(-1,
worker.RESPONSE_TYPE_UNSOLICITED,
request,
calloc(pB_dataLength, 1));
let pB_parcelSize = pB.length - worker.PARCEL_SIZE_SIZE;
let pB_parcelSize = pB.length - buf.PARCEL_SIZE_SIZE;
// First, send an incomplete pA and verifies related data pointer:
let p1 = pA.subarray(0, pA.length - 1);
@ -134,7 +135,7 @@ add_test(function test_incoming_parcel_buffer_overwritten() {
// than 4 octets.
do_check_eq(buf.currentParcelSize, pA_parcelSize);
// buf.readIncoming should contains remaining unconsumed octets count.
do_check_eq(buf.readIncoming, p1.length - worker.PARCEL_SIZE_SIZE);
do_check_eq(buf.readIncoming, p1.length - buf.PARCEL_SIZE_SIZE);
// buf.incomingWriteIndex should be ready to accept the last octet.
do_check_eq(buf.incomingWriteIndex, p1.length);

View File

@ -5,527 +5,11 @@ subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
const ESCAPE = "\uffff";
const RESCTL = "\ufffe";
const LF = "\n";
const CR = "\r";
const SP = " ";
const FF = "\u000c";
function run_test() {
run_next_test();
}
/**
* Verify validity of the national language tables
*/
add_test(function test_nl_locking_shift_tables_validity() {
for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
do_print("Verifying PDU_NL_LOCKING_SHIFT_TABLES[" + lst + "]");
let table = PDU_NL_LOCKING_SHIFT_TABLES[lst];
// Make sure table length is 128, or it will break table lookup algorithm.
do_check_eq(table.length, 128);
// Make sure special values are preserved.
do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
do_check_eq(table[PDU_NL_LINE_FEED], LF);
do_check_eq(table[PDU_NL_CARRIAGE_RETURN], CR);
do_check_eq(table[PDU_NL_SPACE], SP);
}
run_next_test();
});
add_test(function test_nl_single_shift_tables_validity() {
for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
do_print("Verifying PDU_NL_SINGLE_SHIFT_TABLES[" + sst + "]");
let table = PDU_NL_SINGLE_SHIFT_TABLES[sst];
// Make sure table length is 128, or it will break table lookup algorithm.
do_check_eq(table.length, 128);
// Make sure special values are preserved.
do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
do_check_eq(table[PDU_NL_PAGE_BREAK], FF);
do_check_eq(table[PDU_NL_RESERVED_CONTROL], RESCTL);
}
run_next_test();
});
add_test(function test_gsm_sms_strict_7bit_charmap_validity() {
let defaultTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
let defaultShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
for (let from in GSM_SMS_STRICT_7BIT_CHARMAP) {
let to = GSM_SMS_STRICT_7BIT_CHARMAP[from];
do_print("Verifying GSM_SMS_STRICT_7BIT_CHARMAP[\"\\u0x"
+ from.charCodeAt(0).toString(16) + "\"] => \"\\u"
+ to.charCodeAt(0).toString(16) + "\"");
// Make sure "from" is not in default table
do_check_eq(defaultTable.indexOf(from), -1);
do_check_eq(defaultShiftTable.indexOf(from), -1);
// Make sure "to" is in default table
if ((defaultTable.indexOf(to) < 0)
&& (defaultShiftTable.indexOf(to) < 0)) {
do_check_eq(false, true);
}
}
run_next_test();
});
/**
* Verify GsmPDUHelper#readDataCodingScheme.
*/
add_test(function test_GsmPDUHelper_readDataCodingScheme() {
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let helper = worker.GsmPDUHelper;
function test_dcs(dcs, encoding, messageClass, mwi) {
helper.readHexOctet = function () {
return dcs;
}
let msg = {};
helper.readDataCodingScheme(msg);
do_check_eq(msg.dcs, dcs);
do_check_eq(msg.encoding, encoding);
do_check_eq(msg.messageClass, messageClass);
do_check_eq(msg.mwi == null, mwi == null);
if (mwi != null) {
do_check_eq(msg.mwi.active, mwi.active);
do_check_eq(msg.mwi.discard, mwi.discard);
do_check_eq(msg.mwi.msgCount, mwi.msgCount);
}
}
// Group 00xx
// Bit 3 and 2 indicate the character set being used.
test_dcs(0x00, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x04, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x08, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x0C, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
// Bit 4, if set to 0, indicates that bits 1 to 0 are reserved and have no
// message class meaning.
test_dcs(0x01, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x02, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x03, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
// Bit 4, if set to 1, indicates that bits 1 to 0 have a message class meaning.
test_dcs(0x10, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
test_dcs(0x11, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
test_dcs(0x12, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
test_dcs(0x13, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
// Group 01xx
test_dcs(0x50, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
// Group 1000..1011: reserved
test_dcs(0x8F, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x9F, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0xAF, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0xBF, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
// Group 1100: Message Waiting Indication Group: Discard Message
// Bit 3 indicates Indication Sense:
test_dcs(0xC0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: false, discard: true, msgCount: 0});
test_dcs(0xC8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: true, msgCount: -1});
// Bit 2 is reserved, and set to 0:
test_dcs(0xCC, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: true, msgCount: -1});
// Group 1101: Message Waiting Indication Group: Store Message
// Bit 3 indicates Indication Sense:
test_dcs(0xD0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: false, discard: false, msgCount: 0});
test_dcs(0xD8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: false, msgCount: -1});
// Bit 2 is reserved, and set to 0:
test_dcs(0xDC, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: false, msgCount: -1});
// Group 1110: Message Waiting Indication Group: Store Message, UCS2
// Bit 3 indicates Indication Sense:
test_dcs(0xE0, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: false, discard: false, msgCount: 0});
test_dcs(0xE8, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: false, msgCount: -1});
// Bit 2 is reserved, and set to 0:
test_dcs(0xEC, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: false, msgCount: -1});
// Group 1111
test_dcs(0xF0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
test_dcs(0xF1, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
test_dcs(0xF2, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
test_dcs(0xF3, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
test_dcs(0xF4, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
test_dcs(0xF5, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
test_dcs(0xF6, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
test_dcs(0xF7, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
// Bit 3 is reserved and should be set to 0, but if it doesn't we should
// ignore it.
test_dcs(0xF8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
run_next_test();
});
/**
* Verify RadioInterfaceLayer#_countGsm7BitSeptets() and
* GsmPDUHelper#writeStringAsSeptets() algorithm match each other.
*/
add_test(function test_RadioInterfaceLayer__countGsm7BitSeptets() {
let ril = newRadioInterfaceLayer();
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let helper = worker.GsmPDUHelper;
helper.resetOctetWritten = function () {
helper.octetsWritten = 0;
};
helper.writeHexOctet = function () {
helper.octetsWritten++;
};
function do_check_calc(str, expectedCalcLen, lst, sst, strict7BitEncoding, strToWrite) {
do_check_eq(expectedCalcLen,
ril._countGsm7BitSeptets(str,
PDU_NL_LOCKING_SHIFT_TABLES[lst],
PDU_NL_SINGLE_SHIFT_TABLES[sst],
strict7BitEncoding));
helper.resetOctetWritten();
strToWrite = strToWrite || str;
helper.writeStringAsSeptets(strToWrite, 0, lst, sst);
do_check_eq(Math.ceil(expectedCalcLen * 7 / 8), helper.octetsWritten);
}
// Test calculation encoded message length using both locking/single shift tables.
for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst];
let str = langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)
+ langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1);
for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst];
// <escape>, <resctrl> should be ignored.
do_check_calc(ESCAPE + RESCTL, 0, lst, sst);
// Characters defined in locking shift table should be encoded directly.
do_check_calc(str, str.length, lst, sst);
let [str1, str2] = ["", ""];
for (let i = 0; i < langShiftTable.length; i++) {
if ((i == PDU_NL_EXTENDED_ESCAPE) || (i == PDU_NL_RESERVED_CONTROL)) {
continue;
}
let c = langShiftTable[i];
if (langTable.indexOf(c) >= 0) {
str1 += c;
} else {
str2 += c;
}
}
// Characters found in both locking/single shift tables should be
// directly encoded.
do_check_calc(str1, str1.length, lst, sst);
// Characters found only in single shift tables should be encoded as
// <escape><code>, therefore doubles its original length.
do_check_calc(str2, str2.length * 2, lst, sst);
}
}
// Bug 790192: support strict GSM SMS 7-Bit encoding
let str = "", strToWrite = "", gsmLen = 0;
for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
str += c;
strToWrite += GSM_SMS_STRICT_7BIT_CHARMAP[c];
if (PDU_NL_LOCKING_SHIFT_TABLES.indexOf(GSM_SMS_STRICT_7BIT_CHARMAP[c])) {
gsmLen += 1;
} else {
gsmLen += 2;
}
}
do_check_calc(str, gsmLen,
PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT,
true, strToWrite);
run_next_test();
});
/**
* Verify RadioInterfaceLayer#calculateUserDataLength handles national language
* selection correctly.
*/
add_test(function test_RadioInterfaceLayer__calculateUserDataLength() {
let ril = newRadioInterfaceLayer();
function test_calc(str, expected, enabledGsmTableTuples, strict7BitEncoding) {
ril.enabledGsmTableTuples = enabledGsmTableTuples;
let options = ril._calculateUserDataLength(str, strict7BitEncoding);
do_check_eq(expected[0], options.dcs);
do_check_eq(expected[1], options.encodedFullBodyLength);
do_check_eq(expected[2], options.userDataHeaderLength);
do_check_eq(expected[3], options.langIndex);
do_check_eq(expected[4], options.langShiftIndex);
}
// Test UCS fallback
// - No any default enabled nl tables
test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], []);
// - Character not defined in enabled nl tables
test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], [[2, 2]]);
// With GSM default nl tables
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
// - SP is defined in both locking/single shift tables, should be directly
// encoded.
test_calc(SP, [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
// - '^' is only defined in single shift table, should be encoded as
// <escape>^.
test_calc("^", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 0, 0, 0], [[0, 0]]);
// Test userDataHeaderLength calculation
// - Header contains both IEIs
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 6, 1, 1], [[1, 1]]);
// - Header contains only locking shift table IEI
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0]]);
// - Header contains only single shift table IEI
test_calc("^", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 3, 0, 1], [[0, 1]]);
// Test minimum cost nl tables selection
// - 'A' is defined in locking shift table
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0], [2, 0]]);
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[2, 0], [1, 0]]);
// - 'A' is defined in single shift table
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 0], [2, 4]]);
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 4], [2, 0]]);
// - 'A' is defined in locking shift table of one tuple and in single shift
// table of another.
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0], [2, 4]]);
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[2, 4], [1, 0]]);
// Test Bug 733981
// - Case 1, headerLen is in octets, not septets. "\\" is defined in default
// single shift table and Portuguese locking shift table. The original code
// will add headerLen 7(octets), which should be 8(septets), to calculated
// cost and gets 14, which should be 15 in total for the first run. As for
// the second run, it will be undoubtedly 14 in total. With correct fix,
// the best choice should be the second one.
test_calc("\\\\\\\\\\\\\\",
[PDU_DCS_MSG_CODING_7BITS_ALPHABET, 14, 0, 0, 0], [[3, 1], [0, 0]]);
// - Case 2, possible early return non-best choice. The original code will
// get total cost 6 in the first run and returns immediately. With correct
// fix, the best choice should be the second one.
test_calc(ESCAPE + ESCAPE + ESCAPE + ESCAPE + ESCAPE + "\\",
[PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 0, 0, 0], [[3, 0], [0, 0]]);
// Test Bug 790192: support strict GSM SMS 7-Bit encoding
let str = "", gsmLen = 0, udhl = 0;
for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
str += c;
if (PDU_NL_LOCKING_SHIFT_TABLES.indexOf(GSM_SMS_STRICT_7BIT_CHARMAP[c])) {
gsmLen += 1;
} else {
gsmLen += 2;
}
}
if (str.length > PDU_MAX_USER_DATA_UCS2) {
udhl = 5;
}
test_calc(str, [PDU_DCS_MSG_CODING_7BITS_ALPHABET, gsmLen, 0, 0, 0], [[0, 0]], true);
test_calc(str, [PDU_DCS_MSG_CODING_16BITS_ALPHABET, str.length * 2, udhl], [[0, 0]]);
run_next_test();
});
function generateStringOfLength(str, length) {
while (str.length < length) {
if (str.length < (length / 2)) {
str = str + str;
} else {
str = str + str.substr(0, length - str.length);
}
}
return str;
}
/**
* Verify RadioInterfaceLayer#_calculateUserDataLength7Bit multipart handling.
*/
add_test(function test_RadioInterfaceLayer__calculateUserDataLength7Bit_multipart() {
let ril = newRadioInterfaceLayer();
function test_calc(str, expected) {
let options = ril._calculateUserDataLength7Bit(str);
do_check_eq(expected[0], options.encodedFullBodyLength);
do_check_eq(expected[1], options.userDataHeaderLength);
do_check_eq(expected[2], options.segmentMaxSeq);
}
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT),
[PDU_MAX_USER_DATA_7BIT, 0, 1]);
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1),
[PDU_MAX_USER_DATA_7BIT + 1, 5, 2]);
run_next_test();
});
/**
* Verify RadioInterfaceLayer#_fragmentText().
*/
add_test(function test_RadioInterfaceLayer__fragmentText7Bit() {
let ril = newRadioInterfaceLayer();
function test_calc(str, strict7BitEncoding, expectedSegments) {
expectedSegments = expectedSegments || 1;
let options = ril._fragmentText(str, null, strict7BitEncoding);
do_check_eq(expectedSegments, options.segments.length);
}
// 7-Bit
// Boundary checks
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT), false);
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT), true);
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1), false, 2);
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1), true, 2);
// Escaped character
test_calc(generateStringOfLength("{", PDU_MAX_USER_DATA_7BIT / 2), false);
test_calc(generateStringOfLength("{", PDU_MAX_USER_DATA_7BIT / 2 + 1), false, 2);
// Escaped character cannot be separated
test_calc(generateStringOfLength("{", (PDU_MAX_USER_DATA_7BIT - 7) * 2 / 2), false, 3);
// Test headerLen, 7 = Math.ceil(6 * 8 / 7), 6 = headerLen + 1
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT - 7));
test_calc(generateStringOfLength("A", (PDU_MAX_USER_DATA_7BIT - 7) * 2), false, 2);
test_calc(generateStringOfLength("A", (PDU_MAX_USER_DATA_7BIT - 7) * 3), false, 3);
// UCS-2
// Boundary checks
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2));
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2), true);
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2 + 1), false, 2);
// Bug 816082: when strict GSM SMS 7-Bit encoding is enabled, replace unicode
// chars with '*'.
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2 + 1), true, 1);
// UCS2 character cannot be separated
ril.segmentRef16Bit = true;
test_calc(generateStringOfLength("\ua2db", (PDU_MAX_USER_DATA_UCS2 * 2 - 7) * 2 / 2), false, 3);
ril.segmentRef16Bit = false;
// Test Bug 790192: support strict GSM SMS 7-Bit encoding
for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
test_calc(generateStringOfLength(c, PDU_MAX_USER_DATA_7BIT), false, 3);
test_calc(generateStringOfLength(c, PDU_MAX_USER_DATA_7BIT), true);
test_calc(generateStringOfLength(c, PDU_MAX_USER_DATA_UCS2), false);
}
run_next_test();
});
/**
* Verify GsmPDUHelper#writeStringAsSeptets() padding bits handling.
*/
add_test(function test_GsmPDUHelper_writeStringAsSeptets() {
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let helper = worker.GsmPDUHelper;
helper.resetOctetWritten = function () {
helper.octetsWritten = 0;
};
helper.writeHexOctet = function () {
helper.octetsWritten++;
};
let base = "AAAAAAAA"; // Base string of 8 characters long
for (let len = 0; len < 8; len++) {
let str = base.substring(0, len);
for (let paddingBits = 0; paddingBits < 8; paddingBits++) {
do_print("Verifying GsmPDUHelper.writeStringAsSeptets("
+ str + ", " + paddingBits + ", <default>, <default>)");
helper.resetOctetWritten();
helper.writeStringAsSeptets(str, paddingBits, PDU_NL_IDENTIFIER_DEFAULT,
PDU_NL_IDENTIFIER_DEFAULT);
do_check_eq(Math.ceil(((len * 7) + paddingBits) / 8),
helper.octetsWritten);
}
}
run_next_test();
});
/**
* Verify receiving SMS-DELIVERY messages
*/
@ -648,8 +132,8 @@ function add_test_receiving_sms(expected, pdu) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
do_print("body: " + message.body);
do_check_eq(expected, message.body)
do_print("fullBody: " + message.fullBody);
do_check_eq(expected, message.fullBody)
}
});
@ -661,10 +145,15 @@ function add_test_receiving_sms(expected, pdu) {
});
}
let test_receiving_7bit_alphabets__ril;
let test_receiving_7bit_alphabets__worker;
function test_receiving_7bit_alphabets(lst, sst) {
let ril = newRadioInterfaceLayer();
let worker = newWriteHexOctetAsUint8Worker();
if (!test_receiving_7bit_alphabets__ril) {
test_receiving_7bit_alphabets__ril = newRadioInterface();
test_receiving_7bit_alphabets__worker = newWriteHexOctetAsUint8Worker();
}
let ril = test_receiving_7bit_alphabets__ril;
let worker = test_receiving_7bit_alphabets__worker;
let helper = worker.GsmPDUHelper;
let buf = worker.Buf;
@ -693,7 +182,7 @@ function test_receiving_7bit_alphabets(lst, sst) {
}
function test_receiving_ucs2_alphabets(text) {
let worker = newWriteHexOctetAsUint8Worker();
let worker = test_receiving_7bit_alphabets__worker;
let buf = worker.Buf;
function getUCS2RawBytes(expected) {
@ -772,50 +261,3 @@ add_test(function test_sendSMS_UCS2_without_langIndex_langShiftIndex_defined() {
],
});
});
/**
* Verify GsmPDUHelper#readAddress
*/
add_test(function test_GsmPDUHelper_readAddress() {
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let helper = worker.GsmPDUHelper;
function test_address(addrHex, addrString) {
let uint16Array = [];
let ix = 0;
for (let i = 0; i < addrHex.length; ++i) {
uint16Array[i] = addrHex[i].charCodeAt();
}
worker.Buf.readUint16 = function (){
if(ix >= uint16Array.length) {
do_throw("out of range in uint16Array");
}
return uint16Array[ix++];
}
let length = helper.readHexOctet();
let parsedAddr = helper.readAddress(length);
do_check_eq(parsedAddr, addrString);
}
// For AlphaNumeric
test_address("04D01100", "_@");
test_address("04D01000", "\u0394@");
// Direct prepand
test_address("0B914151245584F6", "+14154255486");
test_address("0E914151245584B633", "+14154255486#33");
// PDU_TOA_NATIONAL
test_address("0BA14151245584F6", "14154255486");
run_next_test();
});

View File

@ -0,0 +1,233 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
function run_test() {
run_next_test();
}
/**
* Verify GsmPDUHelper#readDataCodingScheme.
*/
add_test(function test_GsmPDUHelper_readDataCodingScheme() {
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let helper = worker.GsmPDUHelper;
function test_dcs(dcs, encoding, messageClass, mwi) {
helper.readHexOctet = function () {
return dcs;
}
let msg = {};
helper.readDataCodingScheme(msg);
do_check_eq(msg.dcs, dcs);
do_check_eq(msg.encoding, encoding);
do_check_eq(msg.messageClass, messageClass);
do_check_eq(msg.mwi == null, mwi == null);
if (mwi != null) {
do_check_eq(msg.mwi.active, mwi.active);
do_check_eq(msg.mwi.discard, mwi.discard);
do_check_eq(msg.mwi.msgCount, mwi.msgCount);
}
}
// Group 00xx
// Bit 3 and 2 indicate the character set being used.
test_dcs(0x00, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x04, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x08, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x0C, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
// Bit 4, if set to 0, indicates that bits 1 to 0 are reserved and have no
// message class meaning.
test_dcs(0x01, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x02, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x03, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
// Bit 4, if set to 1, indicates that bits 1 to 0 have a message class meaning.
test_dcs(0x10, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
test_dcs(0x11, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
test_dcs(0x12, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
test_dcs(0x13, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
// Group 01xx
test_dcs(0x50, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
// Group 1000..1011: reserved
test_dcs(0x8F, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0x9F, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0xAF, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
test_dcs(0xBF, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
// Group 1100: Message Waiting Indication Group: Discard Message
// Bit 3 indicates Indication Sense:
test_dcs(0xC0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: false, discard: true, msgCount: 0});
test_dcs(0xC8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: true, msgCount: -1});
// Bit 2 is reserved, and set to 0:
test_dcs(0xCC, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: true, msgCount: -1});
// Group 1101: Message Waiting Indication Group: Store Message
// Bit 3 indicates Indication Sense:
test_dcs(0xD0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: false, discard: false, msgCount: 0});
test_dcs(0xD8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: false, msgCount: -1});
// Bit 2 is reserved, and set to 0:
test_dcs(0xDC, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: false, msgCount: -1});
// Group 1110: Message Waiting Indication Group: Store Message, UCS2
// Bit 3 indicates Indication Sense:
test_dcs(0xE0, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: false, discard: false, msgCount: 0});
test_dcs(0xE8, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: false, msgCount: -1});
// Bit 2 is reserved, and set to 0:
test_dcs(0xEC, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
{active: true, discard: false, msgCount: -1});
// Group 1111
test_dcs(0xF0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
test_dcs(0xF1, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
test_dcs(0xF2, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
test_dcs(0xF3, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
test_dcs(0xF4, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
test_dcs(0xF5, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
test_dcs(0xF6, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
test_dcs(0xF7, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
// Bit 3 is reserved and should be set to 0, but if it doesn't we should
// ignore it.
test_dcs(0xF8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
run_next_test();
});
/**
* Verify GsmPDUHelper#writeStringAsSeptets() padding bits handling.
*/
add_test(function test_GsmPDUHelper_writeStringAsSeptets() {
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let helper = worker.GsmPDUHelper;
helper.resetOctetWritten = function () {
helper.octetsWritten = 0;
};
helper.writeHexOctet = function () {
helper.octetsWritten++;
};
let base = "AAAAAAAA"; // Base string of 8 characters long
for (let len = 0; len < 8; len++) {
let str = base.substring(0, len);
for (let paddingBits = 0; paddingBits < 8; paddingBits++) {
do_print("Verifying GsmPDUHelper.writeStringAsSeptets("
+ str + ", " + paddingBits + ", <default>, <default>)");
helper.resetOctetWritten();
helper.writeStringAsSeptets(str, paddingBits, PDU_NL_IDENTIFIER_DEFAULT,
PDU_NL_IDENTIFIER_DEFAULT);
do_check_eq(Math.ceil(((len * 7) + paddingBits) / 8),
helper.octetsWritten);
}
}
run_next_test();
});
/**
* Verify GsmPDUHelper#readAddress
*/
add_test(function test_GsmPDUHelper_readAddress() {
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let helper = worker.GsmPDUHelper;
function test_address(addrHex, addrString) {
let uint16Array = [];
let ix = 0;
for (let i = 0; i < addrHex.length; ++i) {
uint16Array[i] = addrHex[i].charCodeAt();
}
worker.Buf.readUint16 = function (){
if(ix >= uint16Array.length) {
do_throw("out of range in uint16Array");
}
return uint16Array[ix++];
}
let length = helper.readHexOctet();
let parsedAddr = helper.readAddress(length);
do_check_eq(parsedAddr, addrString);
}
// For AlphaNumeric
test_address("04D01100", "_@");
test_address("04D01000", "\u0394@");
// Direct prepand
test_address("0B914151245584F6", "+14154255486");
test_address("0E914151245584B633", "+14154255486#33");
// PDU_TOA_NATIONAL
test_address("0BA14151245584F6", "14154255486");
run_next_test();
});

View File

@ -0,0 +1,77 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
const ESCAPE = "\uffff";
const RESCTL = "\ufffe";
const LF = "\n";
const CR = "\r";
const SP = " ";
const FF = "\u000c";
function run_test() {
run_next_test();
}
/**
* Verify validity of the national language tables
*/
add_test(function test_nl_locking_shift_tables_validity() {
for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
do_print("Verifying PDU_NL_LOCKING_SHIFT_TABLES[" + lst + "]");
let table = PDU_NL_LOCKING_SHIFT_TABLES[lst];
// Make sure table length is 128, or it will break table lookup algorithm.
do_check_eq(table.length, 128);
// Make sure special values are preserved.
do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
do_check_eq(table[PDU_NL_LINE_FEED], LF);
do_check_eq(table[PDU_NL_CARRIAGE_RETURN], CR);
do_check_eq(table[PDU_NL_SPACE], SP);
}
run_next_test();
});
add_test(function test_nl_single_shift_tables_validity() {
for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
do_print("Verifying PDU_NL_SINGLE_SHIFT_TABLES[" + sst + "]");
let table = PDU_NL_SINGLE_SHIFT_TABLES[sst];
// Make sure table length is 128, or it will break table lookup algorithm.
do_check_eq(table.length, 128);
// Make sure special values are preserved.
do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
do_check_eq(table[PDU_NL_PAGE_BREAK], FF);
do_check_eq(table[PDU_NL_RESERVED_CONTROL], RESCTL);
}
run_next_test();
});
add_test(function test_gsm_sms_strict_7bit_charmap_validity() {
let defaultTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
let defaultShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
for (let from in GSM_SMS_STRICT_7BIT_CHARMAP) {
let to = GSM_SMS_STRICT_7BIT_CHARMAP[from];
do_print("Verifying GSM_SMS_STRICT_7BIT_CHARMAP[\"\\u0x"
+ from.charCodeAt(0).toString(16) + "\"] => \"\\u"
+ to.charCodeAt(0).toString(16) + "\"");
// Make sure "from" is not in default table
do_check_eq(defaultTable.indexOf(from), -1);
do_check_eq(defaultShiftTable.indexOf(from), -1);
// Make sure "to" is in default table
if ((defaultTable.indexOf(to) < 0)
&& (defaultShiftTable.indexOf(to) < 0)) {
do_check_eq(false, true);
}
}
run_next_test();
});

View File

@ -0,0 +1,284 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
const ESCAPE = "\uffff";
const RESCTL = "\ufffe";
const SP = " ";
function run_test() {
run_next_test();
}
/**
* Verify RadioInterface#_countGsm7BitSeptets() and
* GsmPDUHelper#writeStringAsSeptets() algorithm match each other.
*/
add_test(function test_RadioInterface__countGsm7BitSeptets() {
let ril = newRadioInterface();
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let helper = worker.GsmPDUHelper;
helper.resetOctetWritten = function () {
helper.octetsWritten = 0;
};
helper.writeHexOctet = function () {
helper.octetsWritten++;
};
function do_check_calc(str, expectedCalcLen, lst, sst, strict7BitEncoding, strToWrite) {
do_check_eq(expectedCalcLen,
ril._countGsm7BitSeptets(str,
PDU_NL_LOCKING_SHIFT_TABLES[lst],
PDU_NL_SINGLE_SHIFT_TABLES[sst],
strict7BitEncoding));
helper.resetOctetWritten();
strToWrite = strToWrite || str;
helper.writeStringAsSeptets(strToWrite, 0, lst, sst);
do_check_eq(Math.ceil(expectedCalcLen * 7 / 8), helper.octetsWritten);
}
// Test calculation encoded message length using both locking/single shift tables.
for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst];
let str = langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)
+ langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1);
for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst];
// <escape>, <resctrl> should be ignored.
do_check_calc(ESCAPE + RESCTL, 0, lst, sst);
// Characters defined in locking shift table should be encoded directly.
do_check_calc(str, str.length, lst, sst);
let [str1, str2] = ["", ""];
for (let i = 0; i < langShiftTable.length; i++) {
if ((i == PDU_NL_EXTENDED_ESCAPE) || (i == PDU_NL_RESERVED_CONTROL)) {
continue;
}
let c = langShiftTable[i];
if (langTable.indexOf(c) >= 0) {
str1 += c;
} else {
str2 += c;
}
}
// Characters found in both locking/single shift tables should be
// directly encoded.
do_check_calc(str1, str1.length, lst, sst);
// Characters found only in single shift tables should be encoded as
// <escape><code>, therefore doubles its original length.
do_check_calc(str2, str2.length * 2, lst, sst);
}
}
// Bug 790192: support strict GSM SMS 7-Bit encoding
let str = "", strToWrite = "", gsmLen = 0;
for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
str += c;
strToWrite += GSM_SMS_STRICT_7BIT_CHARMAP[c];
if (PDU_NL_LOCKING_SHIFT_TABLES.indexOf(GSM_SMS_STRICT_7BIT_CHARMAP[c])) {
gsmLen += 1;
} else {
gsmLen += 2;
}
}
do_check_calc(str, gsmLen,
PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT,
true, strToWrite);
run_next_test();
});
/**
* Verify RadioInterface#calculateUserDataLength handles national language
* selection correctly.
*/
add_test(function test_RadioInterface__calculateUserDataLength() {
let ril = newRadioInterface();
function test_calc(str, expected, enabledGsmTableTuples, strict7BitEncoding) {
ril.enabledGsmTableTuples = enabledGsmTableTuples;
let options = ril._calculateUserDataLength(str, strict7BitEncoding);
do_check_eq(expected[0], options.dcs);
do_check_eq(expected[1], options.encodedFullBodyLength);
do_check_eq(expected[2], options.userDataHeaderLength);
do_check_eq(expected[3], options.langIndex);
do_check_eq(expected[4], options.langShiftIndex);
}
// Test UCS fallback
// - No any default enabled nl tables
test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], []);
// - Character not defined in enabled nl tables
test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], [[2, 2]]);
// With GSM default nl tables
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
// - SP is defined in both locking/single shift tables, should be directly
// encoded.
test_calc(SP, [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
// - '^' is only defined in single shift table, should be encoded as
// <escape>^.
test_calc("^", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 0, 0, 0], [[0, 0]]);
// Test userDataHeaderLength calculation
// - Header contains both IEIs
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 6, 1, 1], [[1, 1]]);
// - Header contains only locking shift table IEI
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0]]);
// - Header contains only single shift table IEI
test_calc("^", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 3, 0, 1], [[0, 1]]);
// Test minimum cost nl tables selection
// - 'A' is defined in locking shift table
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0], [2, 0]]);
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[2, 0], [1, 0]]);
// - 'A' is defined in single shift table
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 0], [2, 4]]);
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 4], [2, 0]]);
// - 'A' is defined in locking shift table of one tuple and in single shift
// table of another.
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0], [2, 4]]);
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[2, 4], [1, 0]]);
// Test Bug 733981
// - Case 1, headerLen is in octets, not septets. "\\" is defined in default
// single shift table and Portuguese locking shift table. The original code
// will add headerLen 7(octets), which should be 8(septets), to calculated
// cost and gets 14, which should be 15 in total for the first run. As for
// the second run, it will be undoubtedly 14 in total. With correct fix,
// the best choice should be the second one.
test_calc("\\\\\\\\\\\\\\",
[PDU_DCS_MSG_CODING_7BITS_ALPHABET, 14, 0, 0, 0], [[3, 1], [0, 0]]);
// - Case 2, possible early return non-best choice. The original code will
// get total cost 6 in the first run and returns immediately. With correct
// fix, the best choice should be the second one.
test_calc(ESCAPE + ESCAPE + ESCAPE + ESCAPE + ESCAPE + "\\",
[PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 0, 0, 0], [[3, 0], [0, 0]]);
// Test Bug 790192: support strict GSM SMS 7-Bit encoding
let str = "", gsmLen = 0, udhl = 0;
for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
str += c;
if (PDU_NL_LOCKING_SHIFT_TABLES.indexOf(GSM_SMS_STRICT_7BIT_CHARMAP[c])) {
gsmLen += 1;
} else {
gsmLen += 2;
}
}
if (str.length > PDU_MAX_USER_DATA_UCS2) {
udhl = 5;
}
test_calc(str, [PDU_DCS_MSG_CODING_7BITS_ALPHABET, gsmLen, 0, 0, 0], [[0, 0]], true);
test_calc(str, [PDU_DCS_MSG_CODING_16BITS_ALPHABET, str.length * 2, udhl], [[0, 0]]);
run_next_test();
});
function generateStringOfLength(str, length) {
while (str.length < length) {
if (str.length < (length / 2)) {
str = str + str;
} else {
str = str + str.substr(0, length - str.length);
}
}
return str;
}
/**
* Verify RadioInterface#_calculateUserDataLength7Bit multipart handling.
*/
add_test(function test_RadioInterface__calculateUserDataLength7Bit_multipart() {
let ril = newRadioInterface();
function test_calc(str, expected) {
let options = ril._calculateUserDataLength7Bit(str);
do_check_eq(expected[0], options.encodedFullBodyLength);
do_check_eq(expected[1], options.userDataHeaderLength);
do_check_eq(expected[2], options.segmentMaxSeq);
}
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT),
[PDU_MAX_USER_DATA_7BIT, 0, 1]);
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1),
[PDU_MAX_USER_DATA_7BIT + 1, 5, 2]);
run_next_test();
});
/**
* Verify RadioInterface#_fragmentText().
*/
add_test(function test_RadioInterface__fragmentText7Bit() {
let ril = newRadioInterface();
function test_calc(str, strict7BitEncoding, expectedSegments) {
expectedSegments = expectedSegments || 1;
let options = ril._fragmentText(str, null, strict7BitEncoding);
do_check_eq(expectedSegments, options.segments.length);
}
// 7-Bit
// Boundary checks
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT), false);
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT), true);
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1), false, 2);
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1), true, 2);
// Escaped character
test_calc(generateStringOfLength("{", PDU_MAX_USER_DATA_7BIT / 2), false);
test_calc(generateStringOfLength("{", PDU_MAX_USER_DATA_7BIT / 2 + 1), false, 2);
// Escaped character cannot be separated
test_calc(generateStringOfLength("{", (PDU_MAX_USER_DATA_7BIT - 7) * 2 / 2), false, 3);
// Test headerLen, 7 = Math.ceil(6 * 8 / 7), 6 = headerLen + 1
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT - 7));
test_calc(generateStringOfLength("A", (PDU_MAX_USER_DATA_7BIT - 7) * 2), false, 2);
test_calc(generateStringOfLength("A", (PDU_MAX_USER_DATA_7BIT - 7) * 3), false, 3);
// UCS-2
// Boundary checks
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2));
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2), true);
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2 + 1), false, 2);
// Bug 816082: when strict GSM SMS 7-Bit encoding is enabled, replace unicode
// chars with '*'.
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2 + 1), true, 1);
// UCS2 character cannot be separated
ril.segmentRef16Bit = true;
test_calc(generateStringOfLength("\ua2db", (PDU_MAX_USER_DATA_UCS2 * 2 - 7) * 2 / 2), false, 3);
ril.segmentRef16Bit = false;
// Test Bug 790192: support strict GSM SMS 7-Bit encoding
for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
test_calc(generateStringOfLength(c, PDU_MAX_USER_DATA_7BIT), false, 3);
test_calc(generateStringOfLength(c, PDU_MAX_USER_DATA_7BIT), true);
test_calc(generateStringOfLength(c, PDU_MAX_USER_DATA_UCS2), false);
}
run_next_test();
});

View File

@ -5,6 +5,11 @@ tail =
[test_ril_worker_buf.js]
[test_ril_worker_icc.js]
[test_ril_worker_sms.js]
# Bug 916067 - B2G RIL: test_ril_worker_sms.js takes too long to finish
skip-if = true
[test_ril_worker_sms_nl_tables.js]
[test_ril_worker_sms_gsmpduhelper.js]
[test_ril_worker_sms_segment_info.js]
[test_ril_worker_mmi.js]
[test_ril_worker_cf.js]
[test_ril_worker_cellbroadcast_config.js]

View File

@ -2,10 +2,6 @@
* 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/. */
const INT32_MAX = 2147483647;
const UINT8_SIZE = 1;
const UINT16_SIZE = 2;
const UINT32_SIZE = 4;
/**
* This object contains helpers buffering incoming data & deconstructing it
@ -21,95 +17,100 @@ const UINT32_SIZE = 4;
*/
let Buf = {
PARCEL_SIZE_SIZE: UINT32_SIZE,
INT32_MAX: 2147483647,
UINT8_SIZE: 1,
UINT16_SIZE: 2,
UINT32_SIZE: 4,
PARCEL_SIZE_SIZE: 4,
PDU_HEX_OCTET_SIZE: 4,
mIncomingBufferLength: 1024,
mIncomingBuffer: null,
mIncomingBytes: null,
mIncomingWriteIndex: 0,
mIncomingReadIndex: 0,
mReadIncoming: 0,
mReadAvailable: 0,
mCurrentParcelSize: 0,
incomingBufferLength: 1024,
incomingBuffer: null,
incomingBytes: null,
incomingWriteIndex: 0,
incomingReadIndex: 0,
readIncoming: 0,
readAvailable: 0,
currentParcelSize: 0,
mOutgoingBufferLength: 1024,
mOutgoingBuffer: null,
mOutgoingBytes: null,
mOutgoingIndex: 0,
mOutgoingBufferCalSizeQueue: null,
outgoingBufferLength: 1024,
outgoingBuffer: null,
outgoingBytes: null,
outgoingIndex: 0,
outgoingBufferCalSizeQueue: null,
_init: function _init() {
this.mIncomingBuffer = new ArrayBuffer(this.mIncomingBufferLength);
this.mOutgoingBuffer = new ArrayBuffer(this.mOutgoingBufferLength);
this.incomingBuffer = new ArrayBuffer(this.incomingBufferLength);
this.outgoingBuffer = new ArrayBuffer(this.outgoingBufferLength);
this.mIncomingBytes = new Uint8Array(this.mIncomingBuffer);
this.mOutgoingBytes = new Uint8Array(this.mOutgoingBuffer);
this.incomingBytes = new Uint8Array(this.incomingBuffer);
this.outgoingBytes = new Uint8Array(this.outgoingBuffer);
// Track where incoming data is read from and written to.
this.mIncomingWriteIndex = 0;
this.mIncomingReadIndex = 0;
this.incomingWriteIndex = 0;
this.incomingReadIndex = 0;
// Leave room for the parcel size for outgoing parcels.
this.mOutgoingIndex = this.PARCEL_SIZE_SIZE;
this.outgoingIndex = this.PARCEL_SIZE_SIZE;
// How many bytes we've read for this parcel so far.
this.mReadIncoming = 0;
this.readIncoming = 0;
// How many bytes available as parcel data.
this.mReadAvailable = 0;
this.readAvailable = 0;
// Size of the incoming parcel. If this is zero, we're expecting a new
// parcel.
this.mCurrentParcelSize = 0;
this.currentParcelSize = 0;
// Queue for storing outgoing override points
this.mOutgoingBufferCalSizeQueue = [];
this.outgoingBufferCalSizeQueue = [];
},
/**
* Mark current mOutgoingIndex as start point for calculation length of data
* written to mOutgoingBuffer.
* Mark current outgoingIndex as start point for calculation length of data
* written to outgoingBuffer.
* Mark can be nested for here uses queue to remember marks.
*
* @param writeFunction
* Function to write data length into mOutgoingBuffer, this function is
* Function to write data length into outgoingBuffer, this function is
* also used to allocate buffer for data length.
* Raw data size(in Uint8) is provided as parameter calling writeFunction.
* If raw data size is not in proper unit for writing, user can adjust
* the length value in writeFunction before writing.
**/
startCalOutgoingSize: function startCalOutgoingSize(writeFunction) {
let sizeInfo = {index: this.mOutgoingIndex,
let sizeInfo = {index: this.outgoingIndex,
write: writeFunction};
// Allocate buffer for data lemgtj.
writeFunction.call(0);
// Get size of data length buffer for it is not counted into data size.
sizeInfo.size = this.mOutgoingIndex - sizeInfo.index;
sizeInfo.size = this.outgoingIndex - sizeInfo.index;
// Enqueue size calculation information.
this.mOutgoingBufferCalSizeQueue.push(sizeInfo);
this.outgoingBufferCalSizeQueue.push(sizeInfo);
},
/**
* Calculate data length since last mark, and write it into mark position.
**/
stopCalOutgoingSize: function stopCalOutgoingSize() {
let sizeInfo = this.mOutgoingBufferCalSizeQueue.pop();
let sizeInfo = this.outgoingBufferCalSizeQueue.pop();
// Remember current mOutgoingIndex.
let currentOutgoingIndex = this.mOutgoingIndex;
// Remember current outgoingIndex.
let currentOutgoingIndex = this.outgoingIndex;
// Calculate data length, in uint8.
let writeSize = this.mOutgoingIndex - sizeInfo.index - sizeInfo.size;
let writeSize = this.outgoingIndex - sizeInfo.index - sizeInfo.size;
// Write data length to mark, use same function for allocating buffer to make
// sure there is no buffer overloading.
this.mOutgoingIndex = sizeInfo.index;
this.outgoingIndex = sizeInfo.index;
sizeInfo.write(writeSize);
// Restore mOutgoingIndex.
this.mOutgoingIndex = currentOutgoingIndex;
// Restore outgoingIndex.
this.outgoingIndex = currentOutgoingIndex;
},
/**
@ -121,34 +122,34 @@ let Buf = {
*/
growIncomingBuffer: function growIncomingBuffer(min_size) {
if (DEBUG) {
debug("Current buffer of " + this.mIncomingBufferLength +
debug("Current buffer of " + this.incomingBufferLength +
" can't handle incoming " + min_size + " bytes.");
}
let oldBytes = this.mIncomingBytes;
this.mIncomingBufferLength =
let oldBytes = this.incomingBytes;
this.incomingBufferLength =
2 << Math.floor(Math.log(min_size)/Math.log(2));
if (DEBUG) debug("New incoming buffer size: " + this.mIncomingBufferLength);
this.mIncomingBuffer = new ArrayBuffer(this.mIncomingBufferLength);
this.mIncomingBytes = new Uint8Array(this.mIncomingBuffer);
if (this.mIncomingReadIndex <= this.mIncomingWriteIndex) {
if (DEBUG) debug("New incoming buffer size: " + this.incomingBufferLength);
this.incomingBuffer = new ArrayBuffer(this.incomingBufferLength);
this.incomingBytes = new Uint8Array(this.incomingBuffer);
if (this.incomingReadIndex <= this.incomingWriteIndex) {
// Read and write index are in natural order, so we can just copy
// the old buffer over to the bigger one without having to worry
// about the indexes.
this.mIncomingBytes.set(oldBytes, 0);
this.incomingBytes.set(oldBytes, 0);
} else {
// The write index has wrapped around but the read index hasn't yet.
// Write whatever the read index has left to read until it would
// circle around to the beginning of the new buffer, and the rest
// behind that.
let head = oldBytes.subarray(this.mIncomingReadIndex);
let tail = oldBytes.subarray(0, this.mIncomingReadIndex);
this.mIncomingBytes.set(head, 0);
this.mIncomingBytes.set(tail, head.length);
this.mIncomingReadIndex = 0;
this.mIncomingWriteIndex += head.length;
let head = oldBytes.subarray(this.incomingReadIndex);
let tail = oldBytes.subarray(0, this.incomingReadIndex);
this.incomingBytes.set(head, 0);
this.incomingBytes.set(tail, head.length);
this.incomingReadIndex = 0;
this.incomingWriteIndex += head.length;
}
if (DEBUG) {
debug("New incoming buffer size is " + this.mIncomingBufferLength);
debug("New incoming buffer size is " + this.incomingBufferLength);
}
},
@ -161,17 +162,17 @@ let Buf = {
*/
growOutgoingBuffer: function growOutgoingBuffer(min_size) {
if (DEBUG) {
debug("Current buffer of " + this.mOutgoingBufferLength +
debug("Current buffer of " + this.outgoingBufferLength +
" is too small.");
}
let oldBytes = this.mOutgoingBytes;
this.mOutgoingBufferLength =
let oldBytes = this.outgoingBytes;
this.outgoingBufferLength =
2 << Math.floor(Math.log(min_size)/Math.log(2));
this.mOutgoingBuffer = new ArrayBuffer(this.mOutgoingBufferLength);
this.mOutgoingBytes = new Uint8Array(this.mOutgoingBuffer);
this.mOutgoingBytes.set(oldBytes, 0);
this.outgoingBuffer = new ArrayBuffer(this.outgoingBufferLength);
this.outgoingBytes = new Uint8Array(this.outgoingBuffer);
this.outgoingBytes.set(oldBytes, 0);
if (DEBUG) {
debug("New outgoing buffer size is " + this.mOutgoingBufferLength);
debug("New outgoing buffer size is " + this.outgoingBufferLength);
}
},
@ -186,10 +187,10 @@ let Buf = {
*
* @param index
* Data position in incoming parcel, valid from 0 to
* mCurrentParcelSize.
* currentParcelSize.
*/
ensureIncomingAvailable: function ensureIncomingAvailable(index) {
if (index >= this.mCurrentParcelSize) {
if (index >= this.currentParcelSize) {
throw new Error("Trying to read data beyond the parcel end!");
} else if (index < 0) {
throw new Error("Trying to read data before the parcel begin!");
@ -203,48 +204,48 @@ let Buf = {
* Seek offset in relative to current position.
*/
seekIncoming: function seekIncoming(offset) {
// Translate to 0..mCurrentParcelSize
let cur = this.mCurrentParcelSize - this.mReadAvailable;
// Translate to 0..currentParcelSize
let cur = this.currentParcelSize - this.readAvailable;
let newIndex = cur + offset;
this.ensureIncomingAvailable(newIndex);
// ... mIncomingReadIndex -->|
// 0 new cur mCurrentParcelSize
// ... incomingReadIndex -->|
// 0 new cur currentParcelSize
// |================|=======|====================|
// |<-- cur -->|<- mReadAvailable ->|
// |<-- newIndex -->|<-- new mReadAvailable -->|
this.mReadAvailable = this.mCurrentParcelSize - newIndex;
// |<-- cur -->|<- readAvailable ->|
// |<-- newIndex -->|<-- new readAvailable -->|
this.readAvailable = this.currentParcelSize - newIndex;
// Translate back:
if (this.mIncomingReadIndex < cur) {
// The mIncomingReadIndex is wrapped.
newIndex += this.mIncomingBufferLength;
if (this.incomingReadIndex < cur) {
// The incomingReadIndex is wrapped.
newIndex += this.incomingBufferLength;
}
newIndex += (this.mIncomingReadIndex - cur);
newIndex %= this.mIncomingBufferLength;
this.mIncomingReadIndex = newIndex;
newIndex += (this.incomingReadIndex - cur);
newIndex %= this.incomingBufferLength;
this.incomingReadIndex = newIndex;
},
readUint8Unchecked: function readUint8Unchecked() {
let value = this.mIncomingBytes[this.mIncomingReadIndex];
this.mIncomingReadIndex = (this.mIncomingReadIndex + 1) %
this.mIncomingBufferLength;
let value = this.incomingBytes[this.incomingReadIndex];
this.incomingReadIndex = (this.incomingReadIndex + 1) %
this.incomingBufferLength;
return value;
},
readUint8: function readUint8() {
// Translate to 0..mCurrentParcelSize
let cur = this.mCurrentParcelSize - this.mReadAvailable;
// Translate to 0..currentParcelSize
let cur = this.currentParcelSize - this.readAvailable;
this.ensureIncomingAvailable(cur);
this.mReadAvailable--;
this.readAvailable--;
return this.readUint8Unchecked();
},
readUint8Array: function readUint8Array(length) {
// Translate to 0..mCurrentParcelSize
let last = this.mCurrentParcelSize - this.mReadAvailable;
// Translate to 0..currentParcelSize
let last = this.currentParcelSize - this.readAvailable;
last += (length - 1);
this.ensureIncomingAvailable(last);
@ -253,7 +254,7 @@ let Buf = {
array[i] = this.readUint8Unchecked();
}
this.mReadAvailable -= length;
this.readAvailable -= length;
return array;
},
@ -277,7 +278,7 @@ let Buf = {
readString: function readString() {
let string_len = this.readUint32();
if (string_len < 0 || string_len >= INT32_MAX) {
if (string_len < 0 || string_len >= this.INT32_MAX) {
return null;
}
let s = "";
@ -328,19 +329,19 @@ let Buf = {
*
* @param index
* Data position in outgoing parcel, valid from 0 to
* mOutgoingBufferLength.
* outgoingBufferLength.
*/
ensureOutgoingAvailable: function ensureOutgoingAvailable(index) {
if (index >= this.mOutgoingBufferLength) {
if (index >= this.outgoingBufferLength) {
this.growOutgoingBuffer(index + 1);
}
},
writeUint8: function writeUint8(value) {
this.ensureOutgoingAvailable(this.mOutgoingIndex);
this.ensureOutgoingAvailable(this.outgoingIndex);
this.mOutgoingBytes[this.mOutgoingIndex] = value;
this.mOutgoingIndex++;
this.outgoingBytes[this.outgoingIndex] = value;
this.outgoingIndex++;
},
writeUint16: function writeUint16(value) {
@ -390,13 +391,13 @@ let Buf = {
* array, but the last thing written. Store the current index off
* to a temporary to be reset after we write the size.
*/
let currentIndex = this.mOutgoingIndex;
this.mOutgoingIndex = 0;
let currentIndex = this.outgoingIndex;
this.outgoingIndex = 0;
this.writeUint8((value >> 24) & 0xff);
this.writeUint8((value >> 16) & 0xff);
this.writeUint8((value >> 8) & 0xff);
this.writeUint8(value & 0xff);
this.mOutgoingIndex = currentIndex;
this.outgoingIndex = currentIndex;
},
copyIncomingToOutgoing: function copyIncomingToOutgoing(length) {
@ -405,36 +406,36 @@ let Buf = {
}
let translatedReadIndexEnd =
this.mCurrentParcelSize - this.mReadAvailable + length - 1;
this.currentParcelSize - this.readAvailable + length - 1;
this.ensureIncomingAvailable(translatedReadIndexEnd);
let translatedWriteIndexEnd = this.mOutgoingIndex + length - 1;
let translatedWriteIndexEnd = this.outgoingIndex + length - 1;
this.ensureOutgoingAvailable(translatedWriteIndexEnd);
let newIncomingReadIndex = this.mIncomingReadIndex + length;
if (newIncomingReadIndex < this.mIncomingBufferLength) {
let newIncomingReadIndex = this.incomingReadIndex + length;
if (newIncomingReadIndex < this.incomingBufferLength) {
// Reading won't cause wrapping, go ahead with builtin copy.
this.mOutgoingBytes
.set(this.mIncomingBytes.subarray(this.mIncomingReadIndex,
newIncomingReadIndex),
this.mOutgoingIndex);
this.outgoingBytes
.set(this.incomingBytes.subarray(this.incomingReadIndex,
newIncomingReadIndex),
this.outgoingIndex);
} else {
// Not so lucky.
newIncomingReadIndex %= this.mIncomingBufferLength;
this.mOutgoingBytes
.set(this.mIncomingBytes.subarray(this.mIncomingReadIndex,
this.mIncomingBufferLength),
this.mOutgoingIndex);
newIncomingReadIndex %= this.incomingBufferLength;
this.outgoingBytes
.set(this.incomingBytes.subarray(this.incomingReadIndex,
this.incomingBufferLength),
this.outgoingIndex);
if (newIncomingReadIndex) {
let firstPartLength = this.mIncomingBufferLength - this.mIncomingReadIndex;
this.mOutgoingBytes.set(this.mIncomingBytes.subarray(0, newIncomingReadIndex),
this.mOutgoingIndex + firstPartLength);
let firstPartLength = this.incomingBufferLength - this.incomingReadIndex;
this.outgoingBytes.set(this.incomingBytes.subarray(0, newIncomingReadIndex),
this.outgoingIndex + firstPartLength);
}
}
this.mIncomingReadIndex = newIncomingReadIndex;
this.mReadAvailable -= length;
this.mOutgoingIndex += length;
this.incomingReadIndex = newIncomingReadIndex;
this.readAvailable -= length;
this.outgoingIndex += length;
},
/**
@ -452,25 +453,25 @@ let Buf = {
// we process any backlog in parcels immediately, before writing
// new data to the buffer. So the only edge case we need to handle
// is when the incoming data is larger than the buffer size.
let minMustAvailableSize = incoming.length + this.mReadIncoming;
if (minMustAvailableSize > this.mIncomingBufferLength) {
let minMustAvailableSize = incoming.length + this.readIncoming;
if (minMustAvailableSize > this.incomingBufferLength) {
this.growIncomingBuffer(minMustAvailableSize);
}
// We can let the typed arrays do the copying if the incoming data won't
// wrap around the edges of the circular buffer.
let remaining = this.mIncomingBufferLength - this.mIncomingWriteIndex;
let remaining = this.incomingBufferLength - this.incomingWriteIndex;
if (remaining >= incoming.length) {
this.mIncomingBytes.set(incoming, this.mIncomingWriteIndex);
this.incomingBytes.set(incoming, this.incomingWriteIndex);
} else {
// The incoming data would wrap around it.
let head = incoming.subarray(0, remaining);
let tail = incoming.subarray(remaining);
this.mIncomingBytes.set(head, this.mIncomingWriteIndex);
this.mIncomingBytes.set(tail, 0);
this.incomingBytes.set(head, this.incomingWriteIndex);
this.incomingBytes.set(tail, 0);
}
this.mIncomingWriteIndex = (this.mIncomingWriteIndex + incoming.length) %
this.mIncomingBufferLength;
this.incomingWriteIndex = (this.incomingWriteIndex + incoming.length) %
this.incomingBufferLength;
},
/**
@ -482,73 +483,73 @@ let Buf = {
processIncoming: function processIncoming(incoming) {
if (DEBUG) {
debug("Received " + incoming.length + " bytes.");
debug("Already read " + this.mReadIncoming);
debug("Already read " + this.readIncoming);
}
this.writeToIncoming(incoming);
this.mReadIncoming += incoming.length;
this.readIncoming += incoming.length;
while (true) {
if (!this.mCurrentParcelSize) {
if (!this.currentParcelSize) {
// We're expecting a new parcel.
if (this.mReadIncoming < this.PARCEL_SIZE_SIZE) {
if (this.readIncoming < this.PARCEL_SIZE_SIZE) {
// We don't know how big the next parcel is going to be, need more
// data.
if (DEBUG) debug("Next parcel size unknown, going to sleep.");
return;
}
this.mCurrentParcelSize = this.readParcelSize();
this.currentParcelSize = this.readParcelSize();
if (DEBUG) {
debug("New incoming parcel of size " + this.mCurrentParcelSize);
debug("New incoming parcel of size " + this.currentParcelSize);
}
// The size itself is not included in the size.
this.mReadIncoming -= this.PARCEL_SIZE_SIZE;
this.readIncoming -= this.PARCEL_SIZE_SIZE;
}
if (this.mReadIncoming < this.mCurrentParcelSize) {
if (this.readIncoming < this.currentParcelSize) {
// We haven't read enough yet in order to be able to process a parcel.
if (DEBUG) debug("Read " + this.mReadIncoming + ", but parcel size is "
+ this.mCurrentParcelSize + ". Going to sleep.");
if (DEBUG) debug("Read " + this.readIncoming + ", but parcel size is "
+ this.currentParcelSize + ". Going to sleep.");
return;
}
// Alright, we have enough data to process at least one whole parcel.
// Let's do that.
let expectedAfterIndex = (this.mIncomingReadIndex + this.mCurrentParcelSize)
% this.mIncomingBufferLength;
let expectedAfterIndex = (this.incomingReadIndex + this.currentParcelSize)
% this.incomingBufferLength;
if (DEBUG) {
let parcel;
if (expectedAfterIndex < this.mIncomingReadIndex) {
let head = this.mIncomingBytes.subarray(this.mIncomingReadIndex);
let tail = this.mIncomingBytes.subarray(0, expectedAfterIndex);
if (expectedAfterIndex < this.incomingReadIndex) {
let head = this.incomingBytes.subarray(this.incomingReadIndex);
let tail = this.incomingBytes.subarray(0, expectedAfterIndex);
parcel = Array.slice(head).concat(Array.slice(tail));
} else {
parcel = Array.slice(this.mIncomingBytes.subarray(
this.mIncomingReadIndex, expectedAfterIndex));
parcel = Array.slice(this.incomingBytes.subarray(
this.incomingReadIndex, expectedAfterIndex));
}
debug("Parcel (size " + this.mCurrentParcelSize + "): " + parcel);
debug("Parcel (size " + this.currentParcelSize + "): " + parcel);
}
if (DEBUG) debug("We have at least one complete parcel.");
try {
this.mReadAvailable = this.mCurrentParcelSize;
this.readAvailable = this.currentParcelSize;
this.processParcel();
} catch (ex) {
if (DEBUG) debug("Parcel handling threw " + ex + "\n" + ex.stack);
}
// Ensure that the whole parcel was consumed.
if (this.mIncomingReadIndex != expectedAfterIndex) {
if (this.incomingReadIndex != expectedAfterIndex) {
if (DEBUG) {
debug("Parcel handler didn't consume whole parcel, " +
Math.abs(expectedAfterIndex - this.mIncomingReadIndex) +
Math.abs(expectedAfterIndex - this.incomingReadIndex) +
" bytes left over");
}
this.mIncomingReadIndex = expectedAfterIndex;
this.incomingReadIndex = expectedAfterIndex;
}
this.mReadIncoming -= this.mCurrentParcelSize;
this.mReadAvailable = 0;
this.mCurrentParcelSize = 0;
this.readIncoming -= this.currentParcelSize;
this.readAvailable = 0;
this.currentParcelSize = 0;
}
},
@ -559,23 +560,23 @@ let Buf = {
// Compute the size of the parcel and write it to the front of the parcel
// where we left room for it. Note that he parcel size does not include
// the size itself.
let parcelSize = this.mOutgoingIndex - this.PARCEL_SIZE_SIZE;
let parcelSize = this.outgoingIndex - this.PARCEL_SIZE_SIZE;
this.writeParcelSize(parcelSize);
// This assumes that postRILMessage will make a copy of the ArrayBufferView
// right away!
let parcel = this.mOutgoingBytes.subarray(0, this.mOutgoingIndex);
let parcel = this.outgoingBytes.subarray(0, this.outgoingIndex);
if (DEBUG) debug("Outgoing parcel: " + Array.slice(parcel));
this.onSendParcel(parcel);
this.mOutgoingIndex = this.PARCEL_SIZE_SIZE;
this.outgoingIndex = this.PARCEL_SIZE_SIZE;
},
getCurrentParcelSize: function getCurrentParcelSize() {
return this.mCurrentParcelSize;
return this.currentParcelSize;
},
getReadAvailable: function getReadAvailable() {
return this.mReadAvailable;
return this.readAvailable;
}
/**

View File

@ -495,6 +495,7 @@ RES_LAYOUT = \
res/layout/notification_progress_text.xml \
res/layout/pin_bookmark_dialog.xml \
res/layout/preference_rightalign_icon.xml \
res/layout/preference_search_engine.xml \
res/layout/preference_search_tip.xml \
res/layout/site_setting_item.xml \
res/layout/site_setting_title.xml \

View File

@ -166,7 +166,7 @@ class SearchEngineRow extends AnimatedHeightLayout {
mSearchEngine = searchEngine;
// Set the search engine icon (e.g., Google) for the row
mIconView.updateImage(mSearchEngine.icon, mSearchEngine.name);
mIconView.updateAndScaleImage(mSearchEngine.icon, mSearchEngine.name);
// Set the initial content description
setDescriptionOnSuggestion(mUserEnteredTextView, mUserEnteredTextView.getText().toString());

View File

@ -10,10 +10,10 @@ import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.preference.Preference;
import android.text.SpannableString;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import org.json.JSONException;
@ -21,6 +21,7 @@ import org.json.JSONObject;
import org.mozilla.gecko.R;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.FaviconView;
/**
* Represents an element in the list of search engines on the preferences menu.
@ -28,9 +29,6 @@ import org.mozilla.gecko.util.ThreadUtils;
public class SearchEnginePreference extends Preference {
private static final String LOGTAG = "SearchEnginePreference";
// Dimensions, in dp, of the icon to display for this engine.
public static int sIconSize;
// Indices in button array of the AlertDialog of the three buttons.
public static final int INDEX_SET_DEFAULT_BUTTON = 0;
public static final int INDEX_REMOVE_BUTTON = 1;
@ -51,6 +49,13 @@ public class SearchEnginePreference extends Preference {
private final SearchPreferenceCategory mParentCategory;
// The icon to display in the prompt when clicked.
private BitmapDrawable mPromptIcon;
// The bitmap backing the drawable above - needed separately for the FaviconView.
private Bitmap mIconBitmap;
private FaviconView mFaviconView;
/**
* Create a preference object to represent a search engine that is attached to category
* containingCategory.
@ -64,8 +69,9 @@ public class SearchEnginePreference extends Preference {
Resources res = getContext().getResources();
// Fetch the icon dimensions from the resource file.
sIconSize = res.getDimensionPixelSize(R.dimen.searchpreferences_icon_size);
// Set the layout resource for this preference - includes a FaviconView.
setLayoutResource(R.layout.preference_search_engine);
setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
@ -84,6 +90,20 @@ public class SearchEnginePreference extends Preference {
res.getString(R.string.pref_search_remove) };
}
/**
* Called by Android when we're bound to the custom view. Allows us to set the custom properties
* of our custom view elements as we desire (We can now use findViewById on them).
*
* @param view The view instance for this Preference object.
*/
@Override
protected void onBindView(View view) {
super.onBindView(view);
// Set the icon in the FaviconView.
mFaviconView = ((FaviconView) view.findViewById(R.id.search_engine_icon));
mFaviconView.updateAndScaleImage(mIconBitmap, getTitle().toString());
}
/**
* Configure this Preference object from the Gecko search engine JSON object.
* @param geckoEngineJSON The Gecko-formatted JSON object representing the search engine.
@ -91,7 +111,7 @@ public class SearchEnginePreference extends Preference {
*/
public void setSearchEngineFromJSON(JSONObject geckoEngineJSON) throws JSONException {
final String engineName = geckoEngineJSON.getString("name");
SpannableString titleSpannable = new SpannableString(engineName);
final SpannableString titleSpannable = new SpannableString(engineName);
mIsImmutableEngine = geckoEngineJSON.getBoolean("immutable");
if (mIsImmutableEngine) {
@ -100,18 +120,14 @@ public class SearchEnginePreference extends Preference {
}
setTitle(titleSpannable);
// setIcon is only available on Honeycomb and up.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// Create a drawable from the iconURI and assign it to this Preference for display.
String iconURI = geckoEngineJSON.getString("iconURI");
Bitmap iconBitmap = BitmapUtils.getBitmapFromDataURI(iconURI);
// The favicon provided may be null or corrupt, if there was a network error or similar.
if (iconBitmap == null) {
return;
}
Bitmap scaledIconBitmap = Bitmap.createScaledBitmap(iconBitmap, sIconSize, sIconSize, false);
BitmapDrawable drawable = new BitmapDrawable(scaledIconBitmap);
setIcon(drawable);
final String iconURI = geckoEngineJSON.getString("iconURI");
// Keep a reference to the bitmap - we'll need it later in onBindView.
try {
mIconBitmap = BitmapUtils.getBitmapFromDataURI(iconURI);
} catch (IllegalArgumentException e) {
Log.e(LOGTAG, "IllegalArgumentException creating Bitmap. Most likely a zero-length bitmap.", e);
} catch (NullPointerException e) {
Log.e(LOGTAG, "NullPointerException creating Bitmap. Most likely a zero-length bitmap.", e);
}
}
@ -176,10 +192,12 @@ public class SearchEnginePreference extends Preference {
}
});
// Copy the icon, if any, from this object to the prompt we produce.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
builder.setIcon(getIcon());
// Copy the icon from this object to the prompt we produce. We lazily create the drawable,
// as the user may not ever actually tap this object.
if (mPromptIcon == null && mIconBitmap != null) {
mPromptIcon = new BitmapDrawable(mFaviconView.getBitmap());
}
builder.setIcon(mPromptIcon);
// We have to construct the dialog itself on the UI thread.
ThreadUtils.postToUiThread(new Runnable() {
@ -221,7 +239,7 @@ public class SearchEnginePreference extends Preference {
*/
private void configureShownDialog() {
// If we are the default engine, disable the "Set as default" button.
TextView defaultButton = (TextView) mDialog.getListView().getChildAt(INDEX_SET_DEFAULT_BUTTON);
final TextView defaultButton = (TextView) mDialog.getListView().getChildAt(INDEX_SET_DEFAULT_BUTTON);
// Disable "Set as default" button if we are already the default.
if (mIsDefaultEngine) {
defaultButton.setEnabled(false);

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingLeft="15dp"
android:paddingRight="?android:attr/scrollbarSize">
<org.mozilla.gecko.widget.FaviconView
android:id="@+id/search_engine_icon"
android:layout_width="@dimen/favicon_bg"
android:layout_height="@dimen/favicon_bg"
android:layout_gravity="center"
android:minWidth="@dimen/favicon_bg"
android:minHeight="@dimen/favicon_bg" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="15dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip">
<TextView android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView android:id="@+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:maxLines="2" />
</LinearLayout>
</LinearLayout>

View File

@ -24,36 +24,12 @@ import java.util.ArrayList;
* To use any of these methods in your test make sure it extends AboutHomeTest instead of BaseTest
*/
abstract class AboutHomeTest extends BaseTest {
protected enum BrowserDataType {BOOKMARKS, HISTORY};
protected enum AboutHomeTabs {MOST_VISITED, MOST_RECENT, TABS_FROM_LAST_TIME, BOOKMARKS, READING_LIST};
protected ArrayList<String> aboutHomeTabs = new ArrayList<String>() {{
add("HISTORY");
add("BOOKMARKS");
add("READING_LIST");
}};
// Labels for the about:home tabs
protected static final String HISTORY_LABEL = "HISTORY";
protected static final String BOOKMARKS_LABEL = "BOOKMARKS";
protected static final String READING_LIST_LABEL = "READING LIST";
protected static final String MOST_RECENT_LABEL = "Most recent";
protected static final String TABS_FROM_LAST_TIME_LABEL = "Open all tabs from last time";
/**
* This method can be used to check if an URL is present in the bookmarks database
*/
protected boolean isBookmark(String url) {
try {
ContentResolver resolver = getActivity().getContentResolver();
ClassLoader classLoader = getActivity().getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method isBookmarked = browserDB.getMethod("isBookmark", ContentResolver.class, String.class);
return (Boolean)isBookmarked.invoke(null, resolver, url);
} catch (Exception e) {
mAsserter.ok(false, "Exception while checking if url is bookmarked: ", e.toString()); // Fail before returning
return false;
}
}
/**
* FIXME: Write new versions of these methods and update their consumers to use the new about:home pages.
@ -65,18 +41,6 @@ abstract class AboutHomeTest extends BaseTest {
return null;
}
protected Uri buildUri(BrowserDataType dataType) {
Uri uri = null;
if (dataType == BrowserDataType.BOOKMARKS || dataType == BrowserDataType.HISTORY) {
uri = Uri.parse("content://@ANDROID_PACKAGE_NAME@.db.browser/" + dataType.toString().toLowerCase());
} else {
mAsserter.ok(false, "The wrong data type has been provided = " + dataType.toString(), "Please provide a BrowserDataType value");
}
uri = uri.buildUpon().appendQueryParameter("profile", "default")
.appendQueryParameter("sync", "true").build();
return uri;
}
/**
* Waits for the given ListView to have a non-empty adapter.
*
@ -121,157 +85,6 @@ abstract class AboutHomeTest extends BaseTest {
return null;
}
/**
* Adds a bookmark, or updates the bookmark title if the url already exists.
*
* The LocalBrowserDB.addBookmark implementation handles updating existing bookmarks.
* Since we don't modify bookmark keywords in tests, we don't need a separate
* implemention of updateBookmark.
*/
protected void addOrUpdateMobileBookmark(String title, String url) {
try {
ContentResolver resolver = getActivity().getContentResolver();
ClassLoader classLoader = getActivity().getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method addBookmark = browserDB.getMethod("addBookmark", ContentResolver.class, String.class, String.class);
addBookmark.invoke(null, resolver, title, url);
mAsserter.ok(true, "Inserting/updating a new bookmark", "Inserting/updating the bookmark with the title = " + title + " and the url = " + url);
} catch (Exception e) {
mAsserter.ok(false, "Exception adding bookmark: ", e.toString());
}
}
/**
* Updates the title and keyword of a bookmark with the given URL.
*
* Warning: This method assumes that there's only one bookmark with the given URL.
*/
protected void updateBookmark(String url, String title, String keyword) {
try {
ContentResolver resolver = getActivity().getContentResolver();
ClassLoader classLoader = getActivity().getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method getBookmarkForUrl = browserDB.getMethod("getBookmarkForUrl", ContentResolver.class, String.class);
// Get the id for the bookmark with the given URL.
Cursor c = null;
try {
c = (Cursor) getBookmarkForUrl.invoke(null, resolver, url);
if (!c.moveToFirst()) {
mAsserter.ok(false, "Getting bookmark with url", "Couldn't find bookmark with url = " + url);
return;
}
int id = c.getInt(c.getColumnIndexOrThrow("_id"));
Method updateBookmark = browserDB.getMethod("updateBookmark", ContentResolver.class, int.class, String.class, String.class, String.class);
updateBookmark.invoke(null, resolver, id, url, title, keyword);
mAsserter.ok(true, "Updating bookmark", "Updating bookmark with url = " + url);
} finally {
if (c != null) {
c.close();
}
}
} catch (Exception e) {
mAsserter.ok(false, "Exception updating bookmark: ", e.toString());
}
}
protected void deleteBookmark(String url) {
try {
ContentResolver resolver = getActivity().getContentResolver();
ClassLoader classLoader = getActivity().getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method removeBookmark = browserDB.getMethod("removeBookmarksWithURL", ContentResolver.class, String.class);
removeBookmark.invoke(null, resolver, url);
} catch (Exception e) {
mAsserter.ok(false, "Exception deleting bookmark: ", e.toString());
}
}
protected void deleteHistoryItem(String url) {
try {
ContentResolver resolver = getActivity().getContentResolver();
ClassLoader classLoader = getActivity().getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method removeHistory = browserDB.getMethod("removeHistoryEntry", ContentResolver.class, String.class);
removeHistory.invoke(null, resolver, url);
} catch (Exception e) {
mAsserter.ok(false, "Exception deleting history item: ", e.toString());
}
}
protected Long getFolderId(String guid) {
ContentResolver resolver = getActivity().getContentResolver();
Long folderId = Long.valueOf(-1);
Uri bookmarksUri = buildUri(BrowserDataType.BOOKMARKS);
Cursor c = null;
try {
c = resolver.query(bookmarksUri,
new String[] { "_id" },
"guid = ?",
new String[] { guid },
null);
if (c.moveToFirst()) {
folderId = c.getLong(c.getColumnIndexOrThrow("_id"));
}
if (folderId == -1) {
mAsserter.ok(false, "Making sure that we got the correct folder", "We didn't get the correct folder id");
}
} finally {
if (c != null) {
c.close();
}
}
return folderId;
}
/**
* @param a BrowserDataType value - either HISTORY or BOOKMARKS
* @return an ArrayList of the urls in the Firefox for Android Bookmarks or History databases
*/
protected ArrayList<String> getBrowserDBUrls(BrowserDataType dataType) {
ArrayList<String> browserData = new ArrayList<String>();
ContentResolver resolver = getActivity().getContentResolver();
ClassLoader classLoader = getActivity().getClassLoader();
Cursor cursor = null;
Uri uri = buildUri(dataType);
if (dataType == BrowserDataType.HISTORY) {
try {
Class browserDBClass = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method getAllVisitedHistory = browserDBClass.getMethod("getAllVisitedHistory", ContentResolver.class);
cursor = (Cursor)getAllVisitedHistory.invoke(null, resolver);
} catch (Exception e) {
mAsserter.ok(false, "Exception while getting history", e.toString());
}
} else if (dataType == BrowserDataType.BOOKMARKS) {
try {
Class browserDBClass = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method getBookmarks = browserDBClass.getMethod("getBookmarksInFolder", ContentResolver.class, Long.TYPE);
cursor = (Cursor)getBookmarks.invoke(null, resolver, getFolderId("mobile"));
} catch (Exception e) {
mAsserter.ok(false, "Exception while getting bookmarks", e.toString());
}
}
if (cursor != null) {
cursor.moveToFirst();
for (int i = 0; i < cursor.getCount(); i++ ) {
// The url field may be null for folders in the structure of the Bookmarks table for Firefox so we should eliminate those
if (cursor.getString(cursor.getColumnIndex("url")) != null) {
browserData.add(cursor.getString(cursor.getColumnIndex("url")));
}
if(!cursor.isLast()) {
cursor.moveToNext();
}
}
} else {
mAsserter.ok(false, "We could not retrieve any data from the database", "The cursor was null");
}
if (cursor != null) {
cursor.close();
}
return browserData;
}
/**
* FIXME: rewrite this to work with fig when rewriting the testBookmarksTab test
@ -352,44 +165,44 @@ abstract class AboutHomeTest extends BaseTest {
ViewPager pager = (ViewPager)mSolo.getView(ViewPager.class, 0);
switch (tab) {
case BOOKMARKS : {
mSolo.clickOnText(BOOKMARKS_LABEL);
mSolo.clickOnText(StringHelper.BOOKMARKS_LABEL);
waitForAboutHomeTab(aboutHomeTabs.indexOf(tab.toString()));
break;
}
case MOST_RECENT: {
mSolo.clickOnText(BOOKMARKS_LABEL);
waitForAboutHomeTab(aboutHomeTabs.indexOf(BOOKMARKS_LABEL));
mSolo.clickOnText(StringHelper.BOOKMARKS_LABEL);
waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.BOOKMARKS_LABEL));
mActions.drag(0, halfWidth, halfHeight, halfHeight);
waitForAboutHomeTab(aboutHomeTabs.indexOf(HISTORY_LABEL));
waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL));
TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0);
mSolo.clickOnView(tabwidget.getChildAt(1));
mAsserter.ok(waitForText(MOST_RECENT_LABEL), "Checking that we are in the most recent tab of about:home", "We are in the most recent tab");
mAsserter.ok(waitForText(StringHelper.MOST_RECENT_LABEL), "Checking that we are in the most recent tab of about:home", "We are in the most recent tab");
break;
}
case READING_LIST: {
mSolo.clickOnText(BOOKMARKS_LABEL);
waitForAboutHomeTab(aboutHomeTabs.indexOf(BOOKMARKS_LABEL));
mSolo.clickOnText(StringHelper.BOOKMARKS_LABEL);
waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.BOOKMARKS_LABEL));
mActions.drag(halfWidth, 0, halfHeight, halfHeight);
waitForAboutHomeTab(aboutHomeTabs.indexOf(tab.toString()));
break;
}
case MOST_VISITED: {
mSolo.clickOnText(BOOKMARKS_LABEL);
waitForAboutHomeTab(aboutHomeTabs.indexOf(BOOKMARKS_LABEL));
mSolo.clickOnText(StringHelper.BOOKMARKS_LABEL);
waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.BOOKMARKS_LABEL));
mActions.drag(0, halfWidth, halfHeight, halfHeight);
waitForAboutHomeTab(aboutHomeTabs.indexOf(HISTORY_LABEL));
waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL));
TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0);
mSolo.clickOnView(tabwidget.getChildAt(0));
break;
}
case TABS_FROM_LAST_TIME: {
mSolo.clickOnText(BOOKMARKS_LABEL);
waitForAboutHomeTab(aboutHomeTabs.indexOf(BOOKMARKS_LABEL));
mSolo.clickOnText(StringHelper.BOOKMARKS_LABEL);
waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.BOOKMARKS_LABEL));
mActions.drag(0, halfWidth, halfHeight, halfHeight);
waitForAboutHomeTab(aboutHomeTabs.indexOf(HISTORY_LABEL));
waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL));
TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0);
mSolo.clickOnView(tabwidget.getChildAt(2));
mAsserter.ok(waitForText(TABS_FROM_LAST_TIME_LABEL), "Checking that we are in the Tabs from last time tab of about:home", "We are in the Tabs from last time tab");
mAsserter.ok(waitForText(StringHelper.TABS_FROM_LAST_TIME_LABEL), "Checking that we are in the Tabs from last time tab of about:home", "We are in the Tabs from last time tab");
break;
}
}

View File

@ -52,28 +52,11 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
private static final int MAX_WAIT_HOME_PAGER_HIDDEN_MS = 10000;
public static final int MAX_WAIT_MS = 3000;
// Note: DEFAULT_BOOKMARKS_TITLES.length == DEFAULT_BOOKMARKS_URLS.length
protected static final String[] DEFAULT_BOOKMARKS_TITLES = new String[] {
"Firefox: About your browser",
"Firefox: Support",
"Firefox: Customize with add-ons"
};
protected static final String[] DEFAULT_BOOKMARKS_URLS = new String[] {
"about:firefox",
"http://support.mozilla.org/en-US/products/mobile",
"https://addons.mozilla.org/en-US/android/"
};
protected static final int DEFAULT_BOOKMARKS_COUNT = DEFAULT_BOOKMARKS_TITLES.length;
// IDs for UI views
private static final String BROWSER_TOOLBAR_ID = "browser_toolbar";
protected static final String URL_EDIT_TEXT_ID = "url_edit_text";
protected static final String URL_BAR_TITLE_ID = "url_bar_title";
// Settings menu paths
protected static final String PRIVACY_LABEL = "Privacy";
protected static final String CLEAR_PRIVATE_DATA_LABEL = "Clear private data";
private static Class<Activity> mLauncherActivityClass;
private Activity mActivity;
protected Solo mSolo;
@ -85,6 +68,8 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
private String mLogFile;
protected String mProfile;
public Device mDevice;
protected DatabaseHelper mDatabaseHelper;
protected StringHelper mStringHelper;
protected void blockForGeckoReady() {
try {
@ -154,6 +139,8 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
mDriver = new FennecNativeDriver(mActivity, mSolo, rootPath);
mActions = new FennecNativeActions(mActivity, mSolo, getInstrumentation(), mAsserter);
mDevice = new Device();
mDatabaseHelper = new DatabaseHelper(mActivity, mAsserter);
mStringHelper = new StringHelper();
}
@Override
@ -617,7 +604,7 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
}
public void clearPrivateData() {
selectSettingsItem(PRIVACY_LABEL, CLEAR_PRIVATE_DATA_LABEL);
selectSettingsItem(StringHelper.PRIVACY_SECTION_LABEL, StringHelper.CLEAR_PRIVATE_DATA_LABEL);
Actions.EventExpecter clearData = mActions.expectGeckoEvent("Sanitize:Finished");
mSolo.clickOnText("Clear data");
clearData.blockForEvent();

View File

@ -10,7 +10,7 @@ import java.lang.reflect.Method;
/**
* This class covers interactions with the context menu opened from web content
*/
abstract class ContentContextMenuTest extends AboutHomeTest {
abstract class ContentContextMenuTest extends BaseTest {
private static final int MAX_TEST_TIMEOUT = 10000;
// This method opens the context menu of any web content. It assumes that the page is already loaded
@ -88,6 +88,6 @@ abstract class ContentContextMenuTest extends AboutHomeTest {
openWebContentContextMenu(bookmarkOption);
mSolo.clickOnText(bookmarkOption);
mAsserter.ok(waitForText("Bookmark added"), "Waiting for the Bookmark added toaster notification", "The notification has been displayed");
mAsserter.ok(isBookmark(link), "Checking if the link has been added as a bookmark", "The link has been bookmarked");
mAsserter.ok(mDatabaseHelper.isBookmark(link), "Checking if the link has been added as a bookmark", "The link has been bookmarked");
}
}

View File

@ -0,0 +1,201 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
import @ANDROID_PACKAGE_NAME@.*;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.test.ActivityInstrumentationTestCase2;
import java.lang.reflect.Method;
import java.util.ArrayList;
class DatabaseHelper {
protected enum BrowserDataType {BOOKMARKS, HISTORY};
private Activity mActivity;
private Assert mAsserter;
public DatabaseHelper(Activity activity, Assert asserter) {
mActivity = activity;
mAsserter = asserter;
}
/**
* This method can be used to check if an URL is present in the bookmarks database
*/
protected boolean isBookmark(String url) {
try {
ContentResolver resolver = mActivity.getContentResolver();
ClassLoader classLoader = mActivity.getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method isBookmarked = browserDB.getMethod("isBookmark", ContentResolver.class, String.class);
return (Boolean)isBookmarked.invoke(null, resolver, url);
} catch (Exception e) {
mAsserter.ok(false, "Exception while checking if url is bookmarked", e.toString());
return false;
}
}
protected Uri buildUri(BrowserDataType dataType) {
Uri uri = null;
if (dataType == BrowserDataType.BOOKMARKS || dataType == BrowserDataType.HISTORY) {
uri = Uri.parse("content://@ANDROID_PACKAGE_NAME@.db.browser/" + dataType.toString().toLowerCase());
} else {
mAsserter.ok(false, "The wrong data type has been provided = " + dataType.toString(), "Please provide the correct data type");
}
uri = uri.buildUpon().appendQueryParameter("profile", "default")
.appendQueryParameter("sync", "true").build();
return uri;
}
/**
* Adds a bookmark, or updates the bookmark title if the url already exists.
*
* The LocalBrowserDB.addBookmark implementation handles updating existing bookmarks.
*/
protected void addOrUpdateMobileBookmark(String title, String url) {
try {
ContentResolver resolver = mActivity.getContentResolver();
ClassLoader classLoader = mActivity.getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method addBookmark = browserDB.getMethod("addBookmark", ContentResolver.class, String.class, String.class);
addBookmark.invoke(null, resolver, title, url);
mAsserter.ok(true, "Inserting/updating a new bookmark", "Inserting/updating the bookmark with the title = " + title + " and the url = " + url);
} catch (Exception e) {
mAsserter.ok(false, "Exception adding bookmark: ", e.toString());
}
}
/**
* Updates the title and keyword of a bookmark with the given URL.
*
* Warning: This method assumes that there's only one bookmark with the given URL.
*/
protected void updateBookmark(String url, String title, String keyword) {
try {
ContentResolver resolver = mActivity.getContentResolver();
ClassLoader classLoader = mActivity.getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method getBookmarkForUrl = browserDB.getMethod("getBookmarkForUrl", ContentResolver.class, String.class);
// Get the id for the bookmark with the given URL.
Cursor c = null;
try {
c = (Cursor) getBookmarkForUrl.invoke(null, resolver, url);
if (!c.moveToFirst()) {
mAsserter.ok(false, "Getting bookmark with url", "Couldn't find bookmark with url = " + url);
return;
}
int id = c.getInt(c.getColumnIndexOrThrow("_id"));
Method updateBookmark = browserDB.getMethod("updateBookmark", ContentResolver.class, int.class, String.class, String.class, String.class);
updateBookmark.invoke(null, resolver, id, url, title, keyword);
mAsserter.ok(true, "Updating bookmark", "Updating bookmark with url = " + url);
} finally {
if (c != null) {
c.close();
}
}
} catch (Exception e) {
mAsserter.ok(false, "Exception updating bookmark: ", e.toString());
}
}
protected void deleteBookmark(String url) {
try {
ContentResolver resolver = mActivity.getContentResolver();
ClassLoader classLoader = mActivity.getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method removeBookmark = browserDB.getMethod("removeBookmarksWithURL", ContentResolver.class, String.class);
removeBookmark.invoke(null, resolver, url);
} catch (Exception e) {
mAsserter.ok(false, "Exception deleting bookmark", e.toString());
}
}
protected void deleteHistoryItem(String url) {
try {
ContentResolver resolver = mActivity.getContentResolver();
ClassLoader classLoader = mActivity.getClassLoader();
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method removeHistory = browserDB.getMethod("removeHistoryEntry", ContentResolver.class, String.class);
removeHistory.invoke(null, resolver, url);
} catch (Exception e) {
mAsserter.ok(false, "Exception deleting history item", e.toString());
}
}
// About the same implementation as getFolderIdFromGuid from LocalBrowserDB because it is declared private and we can't use reflections to access it
protected long getFolderIdFromGuid(String guid) {
ContentResolver resolver = mActivity.getContentResolver();
long folderId = Long.valueOf(-1);
Uri bookmarksUri = buildUri(BrowserDataType.BOOKMARKS);
Cursor c = null;
try {
c = resolver.query(bookmarksUri,
new String[] { "_id" },
"guid = ?",
new String[] { guid },
null);
if (c.moveToFirst()) {
folderId = c.getLong(c.getColumnIndexOrThrow("_id"));
}
if (folderId == -1) {
mAsserter.ok(false, "Trying to get the folder id" ,"We did not get the correct folder id");
}
} finally {
if (c != null) {
c.close();
}
}
return folderId;
}
/**
* @param a BrowserDataType value - either HISTORY or BOOKMARKS
* @return an ArrayList of the urls in the Firefox for Android Bookmarks or History databases
*/
protected ArrayList<String> getBrowserDBUrls(BrowserDataType dataType) {
ArrayList<String> browserData = new ArrayList<String>();
ContentResolver resolver = mActivity.getContentResolver();
ClassLoader classLoader = mActivity.getClassLoader();
Cursor cursor = null;
Uri uri = buildUri(dataType);
if (dataType == BrowserDataType.HISTORY) {
try {
Class browserDBClass = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method getAllVisitedHistory = browserDBClass.getMethod("getAllVisitedHistory", ContentResolver.class);
cursor = (Cursor)getAllVisitedHistory.invoke(null, resolver);
} catch (Exception e) {
mAsserter.ok(false, "Exception while getting history", e.toString());
}
} else if (dataType == BrowserDataType.BOOKMARKS) {
try {
Class browserDBClass = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method getBookmarks = browserDBClass.getMethod("getBookmarksInFolder", ContentResolver.class, Long.TYPE);
cursor = (Cursor)getBookmarks.invoke(null, resolver, getFolderIdFromGuid("mobile"));
} catch (Exception e) {
mAsserter.ok(false, "Exception while getting bookmarks", e.toString());
}
}
if (cursor != null) {
cursor.moveToFirst();
for (int i = 0; i < cursor.getCount(); i++ ) {
// The url field may be null for folders in the structure of the Bookmarks table for Firefox so we should eliminate those
if (cursor.getString(cursor.getColumnIndex("url")) != null) {
browserData.add(cursor.getString(cursor.getColumnIndex("url")));
}
if(!cursor.isLast()) {
cursor.moveToNext();
}
}
} else {
mAsserter.ok(false, "We could not retrieve any data from the database", "The cursor was null");
}
if (cursor != null) {
cursor.close();
}
return browserData;
}
}

View File

@ -0,0 +1,125 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
import @ANDROID_PACKAGE_NAME@.*;
class StringHelper {
// Note: DEFAULT_BOOKMARKS_TITLES.length == DEFAULT_BOOKMARKS_URLS.length
public static final String[] DEFAULT_BOOKMARKS_TITLES = new String[] {
"Firefox: About your browser",
"Firefox: Support",
"Firefox: Customize with add-ons"
};
public static final String[] DEFAULT_BOOKMARKS_URLS = new String[] {
"about:firefox",
"http://support.mozilla.org/en-US/products/mobile",
"https://addons.mozilla.org/en-US/android/"
};
public static final int DEFAULT_BOOKMARKS_COUNT = DEFAULT_BOOKMARKS_TITLES.length;
// Robocop page urls
// Note: please use getAbsoluteUrl(String url) on each robocop url to get the correct url
public static final String ROBOCOP_BIG_LINK_URL = "/robocop/robocop_big_link.html";
public static final String ROBOCOP_BIG_MAILTO_URL = "/robocop/robocop_big_mailto.html";
public static final String ROBOCOP_BLANK_PAGE_01_URL = "/robocop/robocop_blank_01.html";
public static final String ROBOCOP_BLANK_PAGE_02_URL = "/robocop/robocop_blank_02.html";
public static final String ROBOCOP_BLANK_PAGE_03_URL = "/robocop/robocop_blank_03.html";
public static final String ROBOCOP_BOXES_URL = "/robocop/robocop_boxes.html";
public static final String ROBOCOP_GEOLOCATION_URL = "/robocop/robocop_geolocation.html";
public static final String ROBOCOP_LOGIN_URL = "/robocop/robocop_login.html";
public static final String ROBOCOP_OFFLINE_STORAGE_URL = "/robocop/robocop_offline_storage.html";
public static final String ROBOCOP_PICTURE_LINK_URL = "/robocop/robocop_picture_link.html";
public static final String ROBOCOP_SEARCH_URL = "/robocop/robocop_search.html";
public static final String ROBOCOP_TEXT_PAGE_URL = "/robocop/robocop_text_page.html";
// Robocop page titles
public static final String ROBOCOP_BIG_LINK_TITLE = "Big Link";
public static final String ROBOCOP_BIG_MAILTO_TITLE = "Big Mailto";
public static final String ROBOCOP_BLANK_PAGE_01_TITLE = "Browser Blank Page 01";
public static final String ROBOCOP_BLANK_PAGE_02_TITLE = "Browser Blank Page 02";
public static final String ROBOCOP_BLANK_PAGE_03_TITLE = "Browser Blank Page 03";
public static final String ROBOCOP_BOXES_TITLE = "Browser Box test";
public static final String ROBOCOP_GEOLOCATION_TITLE = "Geolocation Test Page";
public static final String ROBOCOP_LOGIN_TITLE = "Robocop Login";
public static final String ROBOCOP_OFFLINE_STORAGE_TITLE = "Robocop offline storage";
public static final String ROBOCOP_PICTURE_LINK_TITLE = "Picture Link";
public static final String ROBOCOP_SEARCH_TITLE = "Robocop Search Engine";
public static final String ROBOCOP_TEXT_PAGE_TITLE = "Robocop Text Page";
// Settings menu strings
// Section labels - ordered as found in the settings menu
public static final String CUSTOMIZE_SECTION_LABEL = "Customize";
public static final String DISPLAY_SECTION_LABEL = "Display";
public static final String PRIVACY_SECTION_LABEL = "Privacy";
public static final String MOZILLA_SECTION_LABEL = "Mozilla";
public static final String DEVELOPER_TOOLS_SECTION_LABEL = "Developer tools";
// Option labels
// Customize
public static final String SYNC_LABEL = "Sync";
public static final String SEARCH_SETTINGS_LABEL = "Search settings";
public static final String IMPORT_FROM_ANDROID_LABEL = "Import from Android";
public static final String TABS_LABEL = "Tabs";
// Display
public static final String TEXT_SIZE_LABEL = "Text size";
public static final String TITLE_BAR_LABEL = "Title bar";
public static final String TEXT_REFLOW_LABEL = "Text reflow";
public static final String CHARACTER_ENCODING_LABEL = "Character encoding";
public static final String PLUGINS_LABEL = "Plugins";
// Privacy
public static final String TRACKING_LABEL = "Tracking";
public static final String COOKIES_LABEL = "Cookies";
public static final String REMEMBER_PASSWORDS_LABEL = "Remeber passwords";
public static final String MASTER_PASWSWORD_LABEL = "Use master password";
public static final String CLEAR_PRIVATE_DATA_LABEL = "Clear private data";
// Mozilla
public static final String ABOUT_LABEL = "About (Fennec|Nightly|Aurora|Firefox Beta|Firefox)";
public static final String FAQS_LABEL = "FAQs";
public static final String FEEDBACK_LABEL = "Give feedback";
public static final String PRODUCT_ANNOUNCEMENTS_LABEL = "Show product announcements";
public static final String LOCATION_SERVICES_LABEL = "Mozilla location services";
public static final String HELTH_REPORT_LABEL = "(Fennec|Nightly|Aurora|Firefox Beta|Firefox) Health Report";
public static final String MY_HEALTH_REPORT_LABEL = "View my Health Report";
// Developer tools
public static final String REMOTE_DEBUGGING_LABEL = "Remote debugging";
public static final String LEARN_MORE_LABEL = "Learn more";
// Labels for the about:home tabs
public static final String HISTORY_LABEL = "HISTORY";
public static final String BOOKMARKS_LABEL = "BOOKMARKS";
public static final String READING_LIST_LABEL = "READING LIST";
public static final String MOST_RECENT_LABEL = "Most recent";
public static final String TABS_FROM_LAST_TIME_LABEL = "Open all tabs from last time";
// Desktop default bookmarks folders
public static final String DESKTOP_FOLDER_LABEL = "Desktop Bookmarks";
public static final String TOOLBAR_FOLDER_LABEL = "Bookmarks Toolbar";
public static final String BOOKMARKS_MENU_FOLDER_LABEL = "Bookmarks Menu";
public static final String UNSORTED_FOLDER_LABEL = "Unsorted Bookmarks";
// Menu items - some of the items are found only on android 2.3 and lower and some only on android 3.0+
public static final String NEW_TAB_LABEL = "New Tab";
public static final String NEW_PRIVATE_TAB_LABEL = "New Private Tab";
public static final String SHARE_LABEL = "Share";
public static final String FIND_IN_PAGE_LABEL = "Find in Page";
public static final String DESKTOP_SITE_LABEL = "Request Desktop Site";
public static final String PDF_LABEL = "Save as PDF";
public static final String DOWNLOADS_LABEL = "Downloads";
public static final String ADDONS_LABEL = "Add-ons";
public static final String APPS_LABEL = "Apps";
public static final String SETTINGS_LABEL = "Settings";
public static final String GUEST_MODE_LABEL = "New Guest Session";
// Android 3.0+
public static final String TOOLS_LABEL = "Tools";
// Android 2.3 and lower only
public static final String MORE_LABEL = "More";
public static final String RELOAD_LABEL = "Reload";
public static final String FORWARD_LABEL = "Forward";
public static final String BOOKMARK_LABEL = "Bookmark";
}

View File

@ -13,24 +13,23 @@ public class testBookmarkKeyword extends AboutHomeTest {
public void testBookmarkKeyword() {
blockForGeckoReady();
final String url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
final String title = "Browser Blank Page 01";
final String url = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
final String keyword = "testkeyword";
// Add a bookmark, and update it to have a keyword.
addOrUpdateMobileBookmark(title, url);
updateBookmark(url, title, keyword);
mDatabaseHelper.addOrUpdateMobileBookmark(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, url);
mDatabaseHelper.updateBookmark(url, StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, keyword);
// Enter the keyword in the urlbar.
inputAndLoadUrl(keyword);
// Wait for the page to load.
waitForText(title);
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
// Make sure the title of the page appeared.
verifyPageTitle(title);
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
// Delete the bookmark to clean up.
deleteBookmark(url);
mDatabaseHelper.deleteBookmark(url);
}
}

View File

@ -14,7 +14,7 @@ public class testBookmarklets extends AboutHomeTest {
}
public void testBookmarklets() {
final String url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
final String url = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
final String title = "alertBookmarklet";
final String js = "javascript:alert(12 + .34)";
boolean alerted;
@ -23,7 +23,7 @@ public class testBookmarklets extends AboutHomeTest {
// load a standard page so bookmarklets work
inputAndLoadUrl(url);
verifyPageTitle("Browser Blank Page 01"); // Waiting for page title to ensure the page is loaded
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE); // Waiting for page title to ensure the page is loaded
// verify that user-entered bookmarklets do *not* work
enterUrl(js);
@ -38,7 +38,7 @@ public class testBookmarklets extends AboutHomeTest {
// add the bookmarklet to the database. there's currently no way to
// add this using the UI, so we go through the content provider.
addOrUpdateMobileBookmark(title, js);
mDatabaseHelper.addOrUpdateMobileBookmark(title, js);
// Open about:home in the Bookmarks page
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
@ -77,6 +77,6 @@ public class testBookmarklets extends AboutHomeTest {
mAsserter.is(alerted, true, "Alert was shown for clicked bookmarklet");
// remove the bookmarklet
deleteBookmark(js);
mDatabaseHelper.deleteBookmark(js);
}
}

View File

@ -4,9 +4,7 @@ package @ANDROID_PACKAGE_NAME@.tests;
import @ANDROID_PACKAGE_NAME@.*;
import java.util.ArrayList;
public class testClearPrivateData extends AboutHomeTest {
private final String BLANK1_TITLE = "Browser Blank Page 01";
private final String BLANK2_TITLE = "Browser Blank Page 02";
public class testClearPrivateData extends PixelTest {
private final int TEST_WAIT_MS = 10000;
@Override
@ -21,13 +19,13 @@ public class testClearPrivateData extends AboutHomeTest {
private void clearHistory() {
// Loading a page and adding a second one as bookmark to have user made bookmarks and history
String blank1 = getAbsoluteUrl("/robocop/robocop_blank_01.html");
String blank2 = getAbsoluteUrl("/robocop/robocop_blank_02.html");
String blank1 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
String blank2 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
inputAndLoadUrl(blank1);
waitForText(BLANK1_TITLE);
loadAndPaint(blank1);
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
addOrUpdateMobileBookmark(BLANK2_TITLE, blank2);
mDatabaseHelper.addOrUpdateMobileBookmark(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE, blank2);
// Checking that the history list is not empty
verifyHistoryCount(1);
@ -37,13 +35,13 @@ public class testClearPrivateData extends AboutHomeTest {
verifyHistoryCount(0);
// Checking that the user made bookmark is not removed
mAsserter.ok(isBookmark(blank2), "Checking that bookmarks have not been removed", "User made bookmarks were not removed with private data");
mAsserter.ok(mDatabaseHelper.isBookmark(blank2), "Checking that bookmarks have not been removed", "User made bookmarks were not removed with private data");
}
private void verifyHistoryCount(final int expectedCount) {
boolean match = waitForTest( new BooleanTest() {
public boolean test() {
return (getBrowserDBUrls(BrowserDataType.HISTORY).size() == expectedCount);
return (mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.HISTORY).size() == expectedCount);
}
}, TEST_WAIT_MS);
mAsserter.ok(match, "Checking that the number of history items is correct", String.valueOf(expectedCount) + " history items present in the database");

View File

@ -42,15 +42,15 @@ public class testImportFromAndroid extends AboutHomeTest {
addData();
// Get the initial bookmarks and history
oldFirefoxBookmarks = getBrowserDBUrls(BrowserDataType.BOOKMARKS);
oldFirefoxHistory = getBrowserDBUrls(BrowserDataType.HISTORY);
oldFirefoxBookmarks = mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.BOOKMARKS);
oldFirefoxHistory = mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.HISTORY);
// Import the bookmarks and history
importDataFromAndroid();
// Get the Android history and the Firefox bookmarks and history lists
firefoxHistory = getBrowserDBUrls(BrowserDataType.HISTORY);
firefoxBookmarks = getBrowserDBUrls(BrowserDataType.BOOKMARKS);
firefoxHistory = mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.HISTORY);
firefoxBookmarks = mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.BOOKMARKS);
/**
* Add a delay to make sure the imported items are added to the array lists
@ -90,7 +90,7 @@ public class testImportFromAndroid extends AboutHomeTest {
// Verify bookmarks are not duplicated
ArrayList<String> verifiedBookmarks = new ArrayList<String>();
firefoxBookmarks = getBrowserDBUrls(BrowserDataType.BOOKMARKS);
firefoxBookmarks = mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.BOOKMARKS);
for (String url:firefoxBookmarks) {
if (verifiedBookmarks.contains(url)) {
mAsserter.ok(false, "Bookmark " + url + " should not be duplicated", "Bookmark is duplicated");
@ -101,7 +101,7 @@ public class testImportFromAndroid extends AboutHomeTest {
}
// Verify history count is not increased after the second import
mAsserter.ok(firefoxHistory.size() == getBrowserDBUrls(BrowserDataType.HISTORY).size(), "The number of history entries was not increased", "None of the items were duplicated");
mAsserter.ok(firefoxHistory.size() == mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.HISTORY).size(), "The number of history entries was not increased", "None of the items were duplicated");
}
private void addData() {
@ -111,7 +111,7 @@ public class testImportFromAndroid extends AboutHomeTest {
for (String url:androidBookmarks) {
// Add every 3rd bookmark to Firefox Mobile
if ((androidBookmarks.indexOf(url) % 3) == 0) {
addOrUpdateMobileBookmark("Bookmark Number " + String.valueOf(androidBookmarks.indexOf(url)), url);
mDatabaseHelper.addOrUpdateMobileBookmark("Bookmark Number" + String.valueOf(androidBookmarks.indexOf(url)), url);
}
}
@ -135,7 +135,7 @@ public class testImportFromAndroid extends AboutHomeTest {
private void importDataFromAndroid() {
waitForText("Enter Search or Address");
selectSettingsItem("Customize", "Import from Android");
selectSettingsItem(StringHelper.CUSTOMIZE_SECTION_LABEL, StringHelper.IMPORT_FROM_ANDROID_LABEL);
// Wait for the Import form Android pop-up to be opened. It has the same title as the option so waiting for the "Cancel" button
waitForText("Cancel");
@ -153,7 +153,7 @@ public class testImportFromAndroid extends AboutHomeTest {
// Import has finished. Waiting to get back to the Settings Menu and looking for the Import&Export subsection
if ("phone".equals(mDevice.type)) {
// Phones don't have headers like tablets, so we need to pop up one more level.
waitForText("Import from Android");
waitForText(StringHelper.IMPORT_FROM_ANDROID_LABEL);
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
}
waitForText("Privacy"); // Settings is a header for the settings menu page. Waiting for Privacy ensures we are back in the top Settings view
@ -196,11 +196,11 @@ public class testImportFromAndroid extends AboutHomeTest {
// Bookmarks
ArrayList<String> androidBookmarks = getAndroidUrls("bookmarks");
for (String url:androidBookmarks) {
deleteBookmark(url);
mDatabaseHelper.deleteBookmark(url);
}
// History
for (String url:androidData) {
deleteHistoryItem(url);
mDatabaseHelper.deleteHistoryItem(url);
}
}

View File

@ -34,7 +34,7 @@ public class testLinkContextMenu extends ContentContextMenuTest {
@Override
public void tearDown() throws Exception {
deleteBookmark(BLANK_PAGE_URL);
mDatabaseHelper.deleteBookmark(BLANK_PAGE_URL);
super.tearDown();
}
}

View File

@ -33,4 +33,10 @@ public class testPictureLinkContextMenu extends ContentContextMenuTest {
verifyShareOption(photoMenuItems[7], PICTURE_PAGE_TITLE); // Test the "Share Link" option
verifyBookmarkLinkOption(photoMenuItems[8],BLANK_PAGE_URL); // Test the "Bookmark Link" option
}
@Override
public void tearDown() throws Exception {
mDatabaseHelper.deleteBookmark(BLANK_PAGE_URL);
super.tearDown();
}
}

View File

@ -154,11 +154,37 @@ public class FaviconView extends ImageView {
formatImage();
}
/**
* Update the displayed image and apply the scaling logic.
* The scaling logic will attempt to resize the image to fit correctly inside the view in a way
* that avoids unreasonable levels of loss of quality.
* Scaling is necessary only when the icon being provided is not drawn from the Favicon cache
* introduced in Bug 914296.
*
* Due to Bug 913746, icons bundled for search engines are not available to the cache, so must
* always have the scaling logic applied here. At the time of writing, this is the only case in
* which the scaling logic here is applied.
*
* @param bitmap The bitmap to display in this favicon view.
* @param key The key to use into the dominant colours cache when selecting a background colour.
*/
public void updateAndScaleImage(Bitmap bitmap, String key) {
updateImageInternal(bitmap, key, true);
}
/**
* Update the image displayed in the Favicon view without scaling. Images larger than the view
* will be centrally cropped. Images smaller than the view will be placed centrally and the
* extra space filled with the dominant colour of the provided image.
*
* @param bitmap The bitmap to display in this favicon view.
* @param key The key to use into the dominant colours cache when selecting a background colour.
*/
public void updateImage(Bitmap bitmap, String key) {
updateImageInternal(bitmap, key, false);
}
public Bitmap getBitmap() {
return mIconBitmap;
}
}

View File

@ -19,6 +19,7 @@ chrome-devtools-frontend.appspot.com: did not receive HSTS header
chrome.google.com: did not receive HSTS header
code.google.com: did not receive HSTS header
codereview.chromium.org: did not receive HSTS header
crowdcurity.com: did not receive HSTS header
crypto.is: did not receive HSTS header
csawctf.poly.edu: did not receive HSTS header
dl.google.com: did not receive HSTS header

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