mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-28 21:28:55 +00:00
Merge m-c to inbound.
This commit is contained in:
commit
d03fb91d02
@ -675,7 +675,7 @@ function getDocumentEncoder(element) {
|
||||
let flags = Ci.nsIDocumentEncoder.SkipInvisibleContent |
|
||||
Ci.nsIDocumentEncoder.OutputRaw |
|
||||
Ci.nsIDocumentEncoder.OutputLFLineBreak |
|
||||
Ci.nsIDocumentEncoder.OutputDropInvisibleBreak;
|
||||
Ci.nsIDocumentEncoder.OutputNonTextContentAsPlaceholder;
|
||||
encoder.init(element.ownerDocument, "text/plain", flags);
|
||||
return encoder;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "8f402e9a5c9a8ba8b5b7d6345952fbb5a7db2d69",
|
||||
"revision": "93d613b62a4697824f918b3625da100d2e177eaa",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ endif
|
||||
# The following tests are disabled because they are unreliable:
|
||||
# browser_bug423833.js is bug 428712
|
||||
# browser_sanitize-download-history.js is bug 432425
|
||||
# browser_aboutHome.js is bug 890409
|
||||
#
|
||||
# browser_sanitizeDialog_treeView.js is disabled until the tree view is added
|
||||
# back to the clear recent history dialog (sanitize.xul), if it ever is (bug
|
||||
@ -71,7 +72,6 @@ MOCHITEST_BROWSER_FILES = \
|
||||
blockPluginVulnerableNoUpdate.xml \
|
||||
blockPluginVulnerableUpdatable.xml \
|
||||
browser_aboutHealthReport.js \
|
||||
browser_aboutHome.js \
|
||||
browser_aboutSyncProgress.js \
|
||||
browser_addKeywordSearch.js \
|
||||
browser_addon_bar_aomlistener.js \
|
||||
|
@ -89,27 +89,8 @@ let gTests = [
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Check that performing a search fires a search event.",
|
||||
setup: function () { },
|
||||
run: function () {
|
||||
let deferred = Promise.defer();
|
||||
let doc = gBrowser.contentDocument;
|
||||
|
||||
doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
|
||||
is(e.detail, doc.documentElement.getAttribute("searchEngineName"), "Detail is search engine name");
|
||||
|
||||
gBrowser.stop();
|
||||
deferred.resolve();
|
||||
}, true, true);
|
||||
|
||||
doc.getElementById("searchText").value = "it works";
|
||||
doc.getElementById("searchSubmit").click();
|
||||
return deferred.promise;
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Check that performing a search records to Firefox Health Report.",
|
||||
desc: "Check that performing a search fires a search event and records to " +
|
||||
"Firefox Health Report.",
|
||||
setup: function () { },
|
||||
run: function () {
|
||||
try {
|
||||
@ -120,46 +101,33 @@ let gTests = [
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let numSearchesBefore = 0;
|
||||
let deferred = Promise.defer();
|
||||
let doc = gBrowser.contentDocument;
|
||||
|
||||
// We rely on the listener in browser.js being installed and fired before
|
||||
// this one. If this ever changes, we should add an executeSoon() or similar.
|
||||
doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
|
||||
executeSoon(gBrowser.stop.bind(gBrowser));
|
||||
let reporter = Components.classes["@mozilla.org/datareporting/service;1"]
|
||||
.getService()
|
||||
.wrappedJSObject
|
||||
.healthReporter;
|
||||
ok(reporter, "Health Reporter instance available.");
|
||||
let engineName = doc.documentElement.getAttribute("searchEngineName");
|
||||
is(e.detail, engineName, "Detail is search engine name");
|
||||
|
||||
reporter.onInit().then(function onInit() {
|
||||
let provider = reporter.getProvider("org.mozilla.searches");
|
||||
ok(provider, "Searches provider is available.");
|
||||
|
||||
let engineName = doc.documentElement.getAttribute("searchEngineName");
|
||||
let id = Services.search.getEngineByName(engineName).identifier;
|
||||
|
||||
let m = provider.getMeasurement("counts", 2);
|
||||
m.getValues().then(function onValues(data) {
|
||||
let now = new Date();
|
||||
ok(data.days.hasDay(now), "Have data for today.");
|
||||
|
||||
let day = data.days.getDay(now);
|
||||
let field = id + ".abouthome";
|
||||
ok(day.has(field), "Have data for about home on this engine.");
|
||||
|
||||
// Note the search from the previous test.
|
||||
is(day.get(field), 2, "Have searches recorded.");
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
gBrowser.stop();
|
||||
|
||||
getNumberOfSearches().then(num => {
|
||||
is(num, numSearchesBefore + 1, "One more search recorded.");
|
||||
deferred.resolve();
|
||||
});
|
||||
}, true, true);
|
||||
|
||||
doc.getElementById("searchText").value = "a search";
|
||||
doc.getElementById("searchSubmit").click();
|
||||
// Get the current number of recorded searches.
|
||||
getNumberOfSearches().then(num => {
|
||||
numSearchesBefore = num;
|
||||
|
||||
info("Perform a search.");
|
||||
doc.getElementById("searchText").value = "a search";
|
||||
doc.getElementById("searchSubmit").click();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
},
|
||||
@ -422,3 +390,54 @@ function promiseBrowserAttributes(aTab)
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of about:home searches recorded for the current day.
|
||||
*
|
||||
* @return {Promise} Returns a promise resolving to the number of searches.
|
||||
*/
|
||||
function getNumberOfSearches() {
|
||||
let reporter = Components.classes["@mozilla.org/datareporting/service;1"]
|
||||
.getService()
|
||||
.wrappedJSObject
|
||||
.healthReporter;
|
||||
ok(reporter, "Health Reporter instance available.");
|
||||
|
||||
return reporter.onInit().then(function onInit() {
|
||||
let provider = reporter.getProvider("org.mozilla.searches");
|
||||
ok(provider, "Searches provider is available.");
|
||||
|
||||
let m = provider.getMeasurement("counts", 2);
|
||||
return m.getValues().then(data => {
|
||||
let now = new Date();
|
||||
let yday = new Date(now);
|
||||
yday.setDate(yday.getDate() - 1);
|
||||
|
||||
// Add the number of searches recorded yesterday to the number of searches
|
||||
// recorded today. This makes the test not fail intermittently when it is
|
||||
// run at midnight and we accidentally compare the number of searches from
|
||||
// different days. Tests are always run with an empty profile so there
|
||||
// are no searches from yesterday, normally. Should the test happen to run
|
||||
// past midnight we make sure to count them in as well.
|
||||
return getNumberOfSearchesByDate(data, now) +
|
||||
getNumberOfSearchesByDate(data, yday);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getNumberOfSearchesByDate(aData, aDate) {
|
||||
if (aData.days.hasDay(aDate)) {
|
||||
let doc = gBrowser.contentDocument;
|
||||
let engineName = doc.documentElement.getAttribute("searchEngineName");
|
||||
let id = Services.search.getEngineByName(engineName).identifier;
|
||||
|
||||
let day = aData.days.getDay(aDate);
|
||||
let field = id + ".abouthome";
|
||||
|
||||
if (day.has(field)) {
|
||||
return day.get(field) || 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // No records found.
|
||||
}
|
||||
|
@ -460,7 +460,11 @@ let SessionStoreInternal = {
|
||||
|
||||
// A Lazy getter for the sessionstore.js backup promise.
|
||||
XPCOMUtils.defineLazyGetter(this, "_backupSessionFileOnce", function () {
|
||||
return _SessionFile.createBackupCopy();
|
||||
// We're creating a backup of sessionstore.js by moving it to .bak
|
||||
// because that's a lot faster than creating a copy. sessionstore.js
|
||||
// would be overwritten shortly afterwards anyway so we can save time
|
||||
// and just move instead of copy.
|
||||
return _SessionFile.moveToBackupPath();
|
||||
});
|
||||
|
||||
// at this point, we've as good as resumed the session, so we can
|
||||
@ -504,12 +508,12 @@ let SessionStoreInternal = {
|
||||
return Task.spawn(function task() {
|
||||
try {
|
||||
// Perform background backup
|
||||
yield _SessionFile.createUpgradeBackupCopy("-" + buildID);
|
||||
yield _SessionFile.createBackupCopy("-" + buildID);
|
||||
|
||||
this._prefBranch.setCharPref(PREF_UPGRADE, buildID);
|
||||
|
||||
// In case of success, remove previous backup.
|
||||
yield _SessionFile.removeUpgradeBackup("-" + latestBackup);
|
||||
yield _SessionFile.removeBackupCopy("-" + latestBackup);
|
||||
} catch (ex) {
|
||||
debug("Could not perform upgrade backup " + ex);
|
||||
debug(ex.stack);
|
||||
@ -772,12 +776,12 @@ let SessionStoreInternal = {
|
||||
this._restoreCount = this._initialState.windows ? this._initialState.windows.length : 0;
|
||||
this.restoreWindow(aWindow, this._initialState,
|
||||
this._isCmdLineEmpty(aWindow, this._initialState));
|
||||
|
||||
// _loadState changed from "stopped" to "running"
|
||||
// force a save operation so that crashes happening during startup are correctly counted
|
||||
this._initialState.session.state = STATE_RUNNING_STR;
|
||||
this._saveStateObject(this._initialState);
|
||||
this._initialState = null;
|
||||
|
||||
// _loadState changed from "stopped" to "running". Save the session's
|
||||
// load state immediately so that crashes happening during startup
|
||||
// are correctly counted.
|
||||
_SessionFile.writeLoadStateOnceAfterStartup(STATE_RUNNING_STR);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
221
browser/components/sessionstore/src/SessionWorker.js
Normal file
221
browser/components/sessionstore/src/SessionWorker.js
Normal file
@ -0,0 +1,221 @@
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* A worker dedicated to handle I/O for Session Store.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
|
||||
let File = OS.File;
|
||||
let Encoder = new TextEncoder();
|
||||
let Decoder = new TextDecoder();
|
||||
|
||||
/**
|
||||
* Communications with the controller.
|
||||
*
|
||||
* Accepts messages:
|
||||
* {fun:function_name, args:array_of_arguments_or_null, id: custom_id}
|
||||
*
|
||||
* Sends messages:
|
||||
* {ok: result, id: custom_id} / {fail: serialized_form_of_OS.File.Error,
|
||||
* id: custom_id}
|
||||
*/
|
||||
self.onmessage = function (msg) {
|
||||
let data = msg.data;
|
||||
if (!(data.fun in Agent)) {
|
||||
throw new Error("Cannot find method " + data.fun);
|
||||
}
|
||||
|
||||
let result;
|
||||
let id = data.id;
|
||||
|
||||
try {
|
||||
result = Agent[data.fun].apply(Agent, data.args);
|
||||
} catch (ex if ex instanceof OS.File.Error) {
|
||||
// Instances of OS.File.Error know how to serialize themselves
|
||||
// (deserialization ensures that we end up with OS-specific
|
||||
// instances of |OS.File.Error|)
|
||||
self.postMessage({fail: OS.File.Error.toMsg(ex), id: id});
|
||||
return;
|
||||
}
|
||||
|
||||
// Other exceptions do not, and should be propagated through DOM's
|
||||
// built-in mechanism for uncaught errors, although this mechanism
|
||||
// may lose interesting information.
|
||||
self.postMessage({ok: result, id: id});
|
||||
};
|
||||
|
||||
let Agent = {
|
||||
// The initial session string as read from disk.
|
||||
initialState: null,
|
||||
|
||||
// Boolean that tells whether we already wrote
|
||||
// the loadState to disk once after startup.
|
||||
hasWrittenLoadStateOnce: false,
|
||||
|
||||
// The path to sessionstore.js
|
||||
path: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"),
|
||||
|
||||
// The path to sessionstore.bak
|
||||
backupPath: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.bak"),
|
||||
|
||||
/**
|
||||
* This method is only intended to be called by _SessionFile.syncRead() and
|
||||
* can be removed when we're not supporting synchronous SessionStore
|
||||
* initialization anymore. When sessionstore.js is read from disk
|
||||
* synchronously the state string must be supplied to the worker manually by
|
||||
* calling this method.
|
||||
*/
|
||||
setInitialState: function (aState) {
|
||||
// _SessionFile.syncRead() should not be called after startup has finished.
|
||||
// Thus we also don't support any setInitialState() calls after we already
|
||||
// wrote the loadState to disk.
|
||||
if (this.hasWrittenLoadStateOnce) {
|
||||
throw new Error("writeLoadStateOnceAfterStartup() must only be called once.");
|
||||
}
|
||||
|
||||
// Initial state might have been filled by read() already but yet we might
|
||||
// be called by _SessionFile.syncRead() before SessionStore.jsm had a chance
|
||||
// to call writeLoadStateOnceAfterStartup(). It's safe to ignore
|
||||
// setInitialState() calls if this happens.
|
||||
if (!this.initialState) {
|
||||
this.initialState = aState;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Read the session from disk.
|
||||
* In case sessionstore.js does not exist, attempt to read sessionstore.bak.
|
||||
*/
|
||||
read: function () {
|
||||
for (let path of [this.path, this.backupPath]) {
|
||||
try {
|
||||
return this.initialState = Decoder.decode(File.read(path));
|
||||
} catch (ex if isNoSuchFileEx(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
}
|
||||
}
|
||||
|
||||
// No sessionstore data files found. Return an empty string.
|
||||
return "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Write the session to disk.
|
||||
*/
|
||||
write: function (stateString) {
|
||||
let bytes = Encoder.encode(stateString);
|
||||
return File.writeAtomic(this.path, bytes, {tmpPath: this.path + ".tmp"});
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes the session state to disk again but changes session.state to
|
||||
* 'running' before doing so. This is intended to be called only once, shortly
|
||||
* after startup so that we detect crashes on startup correctly.
|
||||
*/
|
||||
writeLoadStateOnceAfterStartup: function (loadState) {
|
||||
if (this.hasWrittenLoadStateOnce) {
|
||||
throw new Error("writeLoadStateOnceAfterStartup() must only be called once.");
|
||||
}
|
||||
|
||||
if (!this.initialState) {
|
||||
throw new Error("writeLoadStateOnceAfterStartup() must not be called " +
|
||||
"without a valid session state or before it has been " +
|
||||
"read from disk.");
|
||||
}
|
||||
|
||||
// Make sure we can't call this function twice.
|
||||
this.hasWrittenLoadStateOnce = true;
|
||||
|
||||
let state;
|
||||
try {
|
||||
state = JSON.parse(this.initialState);
|
||||
} finally {
|
||||
this.initialState = null;
|
||||
}
|
||||
|
||||
state.session = state.session || {};
|
||||
state.session.state = loadState;
|
||||
return this.write(JSON.stringify(state));
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves sessionstore.js to sessionstore.bak.
|
||||
*/
|
||||
moveToBackupPath: function () {
|
||||
try {
|
||||
return File.move(this.path, this.backupPath);
|
||||
} catch (ex if isNoSuchFileEx(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a copy of sessionstore.js.
|
||||
*/
|
||||
createBackupCopy: function (ext) {
|
||||
try {
|
||||
return File.copy(this.path, this.backupPath + ext);
|
||||
} catch (ex if isNoSuchFileEx(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a backup copy.
|
||||
*/
|
||||
removeBackupCopy: function (ext) {
|
||||
try {
|
||||
return File.remove(this.backupPath + ext);
|
||||
} catch (ex if isNoSuchFileEx(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Wipes all files holding session data from disk.
|
||||
*/
|
||||
wipe: function () {
|
||||
let exn;
|
||||
|
||||
// Erase session state file
|
||||
try {
|
||||
File.remove(this.path);
|
||||
} catch (ex if isNoSuchFileEx(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
} catch (ex) {
|
||||
// Don't stop immediately.
|
||||
exn = ex;
|
||||
}
|
||||
|
||||
// Erase any backup, any file named "sessionstore.bak[-buildID]".
|
||||
let iter = new File.DirectoryIterator(OS.Constants.Path.profileDir);
|
||||
for (let entry in iter) {
|
||||
if (!entry.isDir && entry.path.startsWith(this.backupPath)) {
|
||||
try {
|
||||
File.remove(entry.path);
|
||||
} catch (ex) {
|
||||
// Don't stop immediately.
|
||||
exn = exn || ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exn) {
|
||||
throw exn;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
function isNoSuchFileEx(aReason) {
|
||||
return aReason instanceof OS.File.Error && aReason.becauseNoSuchFile;
|
||||
}
|
@ -32,6 +32,7 @@ const Ci = Components.interfaces;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/osfile/_PromiseWorker.jsm", this);
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
|
||||
@ -44,66 +45,62 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "Telemetry",
|
||||
"@mozilla.org/base/telemetry;1", "nsITelemetry");
|
||||
|
||||
// An encoder to UTF-8.
|
||||
XPCOMUtils.defineLazyGetter(this, "gEncoder", function () {
|
||||
return new TextEncoder();
|
||||
});
|
||||
// A decoder.
|
||||
XPCOMUtils.defineLazyGetter(this, "gDecoder", function () {
|
||||
return new TextDecoder();
|
||||
});
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
|
||||
"resource://gre/modules/Deprecated.jsm");
|
||||
|
||||
this._SessionFile = {
|
||||
/**
|
||||
* A promise fulfilled once initialization (either synchronous or
|
||||
* asynchronous) is complete.
|
||||
*/
|
||||
promiseInitialized: function SessionFile_initialized() {
|
||||
return SessionFileInternal.promiseInitialized;
|
||||
},
|
||||
/**
|
||||
* Read the contents of the session file, asynchronously.
|
||||
*/
|
||||
read: function SessionFile_read() {
|
||||
read: function () {
|
||||
return SessionFileInternal.read();
|
||||
},
|
||||
/**
|
||||
* Read the contents of the session file, synchronously.
|
||||
*/
|
||||
syncRead: function SessionFile_syncRead() {
|
||||
syncRead: function () {
|
||||
Deprecated.warning(
|
||||
"syncRead is deprecated and will be removed in a future version",
|
||||
"https://bugzilla.mozilla.org/show_bug.cgi?id=532150")
|
||||
return SessionFileInternal.syncRead();
|
||||
},
|
||||
/**
|
||||
* Write the contents of the session file, asynchronously.
|
||||
*/
|
||||
write: function SessionFile_write(aData) {
|
||||
write: function (aData) {
|
||||
return SessionFileInternal.write(aData);
|
||||
},
|
||||
/**
|
||||
* Writes the initial state to disk again only to change the session's load
|
||||
* state. This must only be called once, it will throw an error otherwise.
|
||||
*/
|
||||
writeLoadStateOnceAfterStartup: function (aLoadState) {
|
||||
return SessionFileInternal.writeLoadStateOnceAfterStartup(aLoadState);
|
||||
},
|
||||
/**
|
||||
* Create a backup copy, asynchronously.
|
||||
*/
|
||||
createBackupCopy: function SessionFile_createBackupCopy() {
|
||||
return SessionFileInternal.createBackupCopy();
|
||||
moveToBackupPath: function () {
|
||||
return SessionFileInternal.moveToBackupPath();
|
||||
},
|
||||
/**
|
||||
* Create a backup copy, asynchronously.
|
||||
* This is designed to perform backup on upgrade.
|
||||
*/
|
||||
createUpgradeBackupCopy: function(ext) {
|
||||
return SessionFileInternal.createUpgradeBackupCopy(ext);
|
||||
createBackupCopy: function (ext) {
|
||||
return SessionFileInternal.createBackupCopy(ext);
|
||||
},
|
||||
/**
|
||||
* Remove a backup copy, asynchronously.
|
||||
* This is designed to clean up a backup on upgrade.
|
||||
*/
|
||||
removeUpgradeBackup: function(ext) {
|
||||
return SessionFileInternal.removeUpgradeBackup(ext);
|
||||
removeBackupCopy: function (ext) {
|
||||
return SessionFileInternal.removeBackupCopy(ext);
|
||||
},
|
||||
/**
|
||||
* Wipe the contents of the session file, asynchronously.
|
||||
*/
|
||||
wipe: function SessionFile_wipe() {
|
||||
wipe: function () {
|
||||
return SessionFileInternal.wipe();
|
||||
}
|
||||
};
|
||||
@ -147,11 +144,6 @@ const TaskUtils = {
|
||||
};
|
||||
|
||||
let SessionFileInternal = {
|
||||
/**
|
||||
* A promise fulfilled once initialization is complete
|
||||
*/
|
||||
promiseInitialized: Promise.defer(),
|
||||
|
||||
/**
|
||||
* The path to sessionstore.js
|
||||
*/
|
||||
@ -168,7 +160,7 @@ let SessionFileInternal = {
|
||||
* A path to read the file from.
|
||||
* @returns string if successful, undefined otherwise.
|
||||
*/
|
||||
readAuxSync: function ssfi_readAuxSync(aPath) {
|
||||
readAuxSync: function (aPath) {
|
||||
let text;
|
||||
try {
|
||||
let file = new FileUtils.File(aPath);
|
||||
@ -197,7 +189,7 @@ let SessionFileInternal = {
|
||||
* happened between backup and write), attempt to read the sessionstore.bak
|
||||
* instead.
|
||||
*/
|
||||
syncRead: function ssfi_syncRead() {
|
||||
syncRead: function () {
|
||||
// Start measuring the duration of the synchronous read.
|
||||
TelemetryStopwatch.start("FX_SESSION_RESTORE_SYNC_READ_FILE_MS");
|
||||
// First read the sessionstore.js.
|
||||
@ -208,83 +200,26 @@ let SessionFileInternal = {
|
||||
}
|
||||
// Finish the telemetry probe and return an empty string.
|
||||
TelemetryStopwatch.finish("FX_SESSION_RESTORE_SYNC_READ_FILE_MS");
|
||||
return text || "";
|
||||
text = text || "";
|
||||
|
||||
// The worker needs to know the initial state read from
|
||||
// disk so that writeLoadStateOnceAfterStartup() works.
|
||||
SessionWorker.post("setInitialState", [text]);
|
||||
return text;
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility function to safely read a file asynchronously.
|
||||
* @param aPath
|
||||
* A path to read the file from.
|
||||
* @param aReadOptions
|
||||
* Read operation options.
|
||||
* |outExecutionDuration| option will be reused and can be
|
||||
* incrementally updated by the worker process.
|
||||
* @returns string if successful, undefined otherwise.
|
||||
*/
|
||||
readAux: function ssfi_readAux(aPath, aReadOptions) {
|
||||
let self = this;
|
||||
return TaskUtils.spawn(function () {
|
||||
let text;
|
||||
try {
|
||||
let bytes = yield OS.File.read(aPath, undefined, aReadOptions);
|
||||
text = gDecoder.decode(bytes);
|
||||
// If the file is read successfully, add a telemetry probe based on
|
||||
// the updated duration value of the |outExecutionDuration| option.
|
||||
let histogram = Telemetry.getHistogramById(
|
||||
"FX_SESSION_RESTORE_READ_FILE_MS");
|
||||
histogram.add(aReadOptions.outExecutionDuration);
|
||||
} catch (ex if self._isNoSuchFile(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
throw new Task.Result(text);
|
||||
});
|
||||
read: function () {
|
||||
return SessionWorker.post("read").then(msg => msg.ok);
|
||||
},
|
||||
|
||||
/**
|
||||
* Read the sessionstore file asynchronously.
|
||||
*
|
||||
* In case sessionstore.js file does not exist or is corrupted (something
|
||||
* happened between backup and write), attempt to read the sessionstore.bak
|
||||
* instead.
|
||||
*/
|
||||
read: function ssfi_read() {
|
||||
let self = this;
|
||||
return TaskUtils.spawn(function task() {
|
||||
// Specify |outExecutionDuration| option to hold the combined duration of
|
||||
// the asynchronous reads off the main thread (of both sessionstore.js and
|
||||
// sessionstore.bak, if necessary). If sessionstore.js does not exist or
|
||||
// is corrupted, |outExecutionDuration| will register the time it took to
|
||||
// attempt to read the file. It will then be subsequently incremented by
|
||||
// the read time of sessionsore.bak.
|
||||
let readOptions = {
|
||||
outExecutionDuration: null
|
||||
};
|
||||
// First read the sessionstore.js.
|
||||
let text = yield self.readAux(self.path, readOptions);
|
||||
if (typeof text === "undefined") {
|
||||
// If sessionstore.js does not exist or is corrupted, read the
|
||||
// sessionstore.bak.
|
||||
text = yield self.readAux(self.backupPath, readOptions);
|
||||
}
|
||||
// Return either the content of the sessionstore.bak if it was read
|
||||
// successfully or an empty string otherwise.
|
||||
throw new Task.Result(text || "");
|
||||
});
|
||||
},
|
||||
|
||||
write: function ssfi_write(aData) {
|
||||
write: function (aData) {
|
||||
let refObj = {};
|
||||
let self = this;
|
||||
return TaskUtils.spawn(function task() {
|
||||
TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
|
||||
TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
|
||||
|
||||
let bytes = gEncoder.encode(aData);
|
||||
|
||||
try {
|
||||
let promise = OS.File.writeAtomic(self.path, bytes, {tmpPath: self.path + ".tmp"});
|
||||
let promise = SessionWorker.post("write", [aData]);
|
||||
// At this point, we measure how long we stop the main thread
|
||||
TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
|
||||
|
||||
@ -294,93 +229,51 @@ let SessionFileInternal = {
|
||||
} catch (ex) {
|
||||
TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
|
||||
TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
|
||||
Cu.reportError("Could not write session state file " + self.path
|
||||
+ ": " + aReason);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
createBackupCopy: function ssfi_createBackupCopy() {
|
||||
let backupCopyOptions = {
|
||||
outExecutionDuration: null
|
||||
};
|
||||
let self = this;
|
||||
return TaskUtils.spawn(function task() {
|
||||
try {
|
||||
yield OS.File.move(self.path, self.backupPath, backupCopyOptions);
|
||||
Telemetry.getHistogramById("FX_SESSION_RESTORE_BACKUP_FILE_MS").add(
|
||||
backupCopyOptions.outExecutionDuration);
|
||||
} catch (ex if self._isNoSuchFile(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
} catch (ex) {
|
||||
Cu.reportError("Could not backup session state file: " + ex);
|
||||
throw ex;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
createUpgradeBackupCopy: function(ext) {
|
||||
return TaskUtils.spawn(function task() {
|
||||
try {
|
||||
yield OS.File.copy(this.path, this.backupPath + ext);
|
||||
} catch (ex if this._isNoSuchFile(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
} catch (ex) {
|
||||
Cu.reportError("Could not backup session state file to " +
|
||||
dest + ": " + ex);
|
||||
throw ex;
|
||||
Cu.reportError("Could not write session state file " + this.path
|
||||
+ ": " + ex);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
removeUpgradeBackup: function(ext) {
|
||||
return TaskUtils.spawn(function task() {
|
||||
try {
|
||||
yield OS.File.remove(this.backupPath + ext);
|
||||
} catch (ex if this._isNoSuchFile(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
}
|
||||
}.bind(this));
|
||||
writeLoadStateOnceAfterStartup: function (aLoadState) {
|
||||
return SessionWorker.post("writeLoadStateOnceAfterStartup", [aLoadState]);
|
||||
},
|
||||
|
||||
wipe: function ssfi_wipe() {
|
||||
let self = this;
|
||||
return TaskUtils.spawn(function task() {
|
||||
let exn;
|
||||
// Erase session state file
|
||||
try {
|
||||
yield OS.File.remove(self.path);
|
||||
} catch (ex if self._isNoSuchFile(ex)) {
|
||||
// Ignore exceptions about non-existent files.
|
||||
} catch (ex) {
|
||||
// Report error, don't stop immediately
|
||||
Cu.reportError("Could not remove session state file: " + ex);
|
||||
exn = ex;
|
||||
}
|
||||
|
||||
// Erase any backup, any file named "sessionstore.bak[-buildID]".
|
||||
let iterator = new OS.File.DirectoryIterator(OS.Constants.Path.profileDir);
|
||||
for (let promise of iterator) {
|
||||
let entry = yield promise;
|
||||
if (!entry.isDir && entry.path.startsWith(self.backupPath)) {
|
||||
try {
|
||||
yield OS.File.remove(entry.path);
|
||||
} catch (ex) {
|
||||
// Report error, don't stop immediately
|
||||
Cu.reportError("Could not remove backup file " + entry.path + " : " + ex);
|
||||
exn = exn || ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exn) {
|
||||
throw exn;
|
||||
}
|
||||
});
|
||||
|
||||
moveToBackupPath: function () {
|
||||
return SessionWorker.post("moveToBackupPath");
|
||||
},
|
||||
|
||||
_isNoSuchFile: function ssfi_isNoSuchFile(aReason) {
|
||||
return aReason instanceof OS.File.Error && aReason.becauseNoSuchFile;
|
||||
createBackupCopy: function (ext) {
|
||||
return SessionWorker.post("createBackupCopy", [ext]);
|
||||
},
|
||||
|
||||
removeBackupCopy: function (ext) {
|
||||
return SessionWorker.post("removeBackupCopy", [ext]);
|
||||
},
|
||||
|
||||
wipe: function () {
|
||||
return SessionWorker.post("wipe");
|
||||
}
|
||||
};
|
||||
|
||||
// Interface to a dedicated thread handling I/O
|
||||
let SessionWorker = (function () {
|
||||
let worker = new PromiseWorker("resource:///modules/sessionstore/SessionWorker.js",
|
||||
OS.Shared.LOG.bind("SessionWorker"));
|
||||
return {
|
||||
post: function post(...args) {
|
||||
let promise = worker.post.apply(worker, args);
|
||||
return promise.then(
|
||||
null,
|
||||
function onError(error) {
|
||||
// Decode any serialized error
|
||||
if (error instanceof PromiseWorker.WorkerError) {
|
||||
throw OS.File.Error.fromMsg(error.data);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -16,6 +16,7 @@ EXTRA_JS_MODULES = [
|
||||
'DocumentUtils.jsm',
|
||||
'SessionMigration.jsm',
|
||||
'SessionStorage.jsm',
|
||||
'SessionWorker.js',
|
||||
'XPathGenerator.jsm',
|
||||
'_SessionFile.jsm',
|
||||
]
|
||||
|
@ -196,18 +196,13 @@ function test() {
|
||||
options = {private: true};
|
||||
}
|
||||
|
||||
let newWin = OpenBrowserWindow(options);
|
||||
newWin.addEventListener("load", function(aEvent) {
|
||||
newWin.removeEventListener("load", arguments.callee, false);
|
||||
newWin.gBrowser.addEventListener("load", function(aEvent) {
|
||||
newWin.gBrowser.removeEventListener("load", arguments.callee, true);
|
||||
TEST_URLS.forEach(function (url) {
|
||||
newWin.gBrowser.addTab(url);
|
||||
});
|
||||
whenNewWindowLoaded(options, function (newWin) {
|
||||
TEST_URLS.forEach(function (url) {
|
||||
newWin.gBrowser.addTab(url);
|
||||
});
|
||||
|
||||
executeSoon(function() testFn(newWin));
|
||||
}, true);
|
||||
}, false);
|
||||
executeSoon(() => testFn(newWin));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -230,20 +225,16 @@ function test() {
|
||||
|
||||
// Open a new window
|
||||
// The previously closed window should be restored
|
||||
newWin = OpenBrowserWindow({});
|
||||
newWin.addEventListener("load", function() {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
executeSoon(function() {
|
||||
is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
|
||||
"Restored window in-session with otherpopup windows around");
|
||||
whenNewWindowLoaded({}, function (newWin) {
|
||||
is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
|
||||
"Restored window in-session with otherpopup windows around");
|
||||
|
||||
// Cleanup
|
||||
newWin.close();
|
||||
// Cleanup
|
||||
newWin.close();
|
||||
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
}, true);
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -259,32 +250,24 @@ function test() {
|
||||
// Enter private browsing mode
|
||||
// Open a new window.
|
||||
// The previously closed window should NOT be restored
|
||||
newWin = OpenBrowserWindow({private: true});
|
||||
newWin.addEventListener("load", function() {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
executeSoon(function() {
|
||||
is(newWin.gBrowser.browsers.length, 1,
|
||||
"Did not restore in private browing mode");
|
||||
whenNewWindowLoaded({private: true}, function (newWin) {
|
||||
is(newWin.gBrowser.browsers.length, 1,
|
||||
"Did not restore in private browing mode");
|
||||
|
||||
// Cleanup
|
||||
newWin.BrowserTryToCloseWindow();
|
||||
// Cleanup
|
||||
newWin.BrowserTryToCloseWindow();
|
||||
|
||||
// Exit private browsing mode again
|
||||
newWin = OpenBrowserWindow({});
|
||||
newWin.addEventListener("load", function() {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
executeSoon(function() {
|
||||
is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
|
||||
"Restored after leaving private browsing again");
|
||||
// Exit private browsing mode again
|
||||
whenNewWindowLoaded({}, function (newWin) {
|
||||
is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
|
||||
"Restored after leaving private browsing again");
|
||||
|
||||
newWin.close();
|
||||
newWin.close();
|
||||
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
}, true);
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -312,21 +295,17 @@ function test() {
|
||||
popup2.close();
|
||||
|
||||
// open a new window the previously closed window should be restored to
|
||||
newWin = OpenBrowserWindow({});
|
||||
newWin.addEventListener("load", function() {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
executeSoon(function() {
|
||||
is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
|
||||
"Restored window and associated tabs in session");
|
||||
whenNewWindowLoaded({}, function (newWin) {
|
||||
is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
|
||||
"Restored window and associated tabs in session");
|
||||
|
||||
// Cleanup
|
||||
newWin.close();
|
||||
popup.close();
|
||||
// Cleanup
|
||||
newWin.close();
|
||||
popup.close();
|
||||
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
}, true);
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
}, true);
|
||||
}, false);
|
||||
});
|
||||
@ -366,22 +345,18 @@ function test() {
|
||||
// but instead a new window is opened without restoring anything
|
||||
popup.close();
|
||||
|
||||
let newWin = OpenBrowserWindow({});
|
||||
newWin.addEventListener("load", function() {
|
||||
newWin.removeEventListener("load", arguments.callee, true);
|
||||
executeSoon(function() {
|
||||
isnot(newWin.gBrowser.browsers.length, 2,
|
||||
"Did not restore the popup window");
|
||||
is(TEST_URLS.indexOf(newWin.gBrowser.browsers[0].currentURI.spec), -1,
|
||||
"Did not restore the popup window (2)");
|
||||
whenNewWindowLoaded({}, function (newWin) {
|
||||
isnot(newWin.gBrowser.browsers.length, 2,
|
||||
"Did not restore the popup window");
|
||||
is(TEST_URLS.indexOf(newWin.gBrowser.browsers[0].currentURI.spec), -1,
|
||||
"Did not restore the popup window (2)");
|
||||
|
||||
// Cleanup
|
||||
newWin.close();
|
||||
// Cleanup
|
||||
newWin.close();
|
||||
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
}, true);
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
}, true);
|
||||
}, false);
|
||||
}, true);
|
||||
@ -402,27 +377,23 @@ function test() {
|
||||
|
||||
newWin = undoCloseWindow(0);
|
||||
|
||||
newWin2 = OpenBrowserWindow({});
|
||||
newWin2.addEventListener("load", function() {
|
||||
newWin2.removeEventListener("load", arguments.callee, true);
|
||||
executeSoon(function() {
|
||||
is(newWin2.gBrowser.browsers.length, 1,
|
||||
"Did not restore, as undoCloseWindow() was last called");
|
||||
is(TEST_URLS.indexOf(newWin2.gBrowser.browsers[0].currentURI.spec), -1,
|
||||
"Did not restore, as undoCloseWindow() was last called (2)");
|
||||
whenNewWindowLoaded({}, function (newWin2) {
|
||||
is(newWin2.gBrowser.browsers.length, 1,
|
||||
"Did not restore, as undoCloseWindow() was last called");
|
||||
is(TEST_URLS.indexOf(newWin2.gBrowser.browsers[0].currentURI.spec), -1,
|
||||
"Did not restore, as undoCloseWindow() was last called (2)");
|
||||
|
||||
browserWindowsCount([2, 3], "browser windows while running testOpenCloseRestoreFromPopup");
|
||||
browserWindowsCount([2, 3], "browser windows while running testOpenCloseRestoreFromPopup");
|
||||
|
||||
// Cleanup
|
||||
newWin.close();
|
||||
newWin2.close();
|
||||
// Cleanup
|
||||
newWin.close();
|
||||
newWin2.close();
|
||||
|
||||
browserWindowsCount([0, 1], "browser windows while running testOpenCloseRestoreFromPopup");
|
||||
browserWindowsCount([0, 1], "browser windows while running testOpenCloseRestoreFromPopup");
|
||||
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
}, true);
|
||||
// Next please
|
||||
executeSoon(nextFn);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -10,37 +10,34 @@ function test() {
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let window_B = openDialog(location, "_blank", "chrome,all,dialog=no");
|
||||
window_B.addEventListener("load", function(aEvent) {
|
||||
window_B.removeEventListener("load", arguments.callee, false);
|
||||
whenNewWindowLoaded({ private: false }, function (window_B) {
|
||||
waitForFocus(function() {
|
||||
// Add identifying information to window_B
|
||||
ss.setWindowValue(window_B, uniqKey, uniqVal);
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
let selectedWindow = state.windows[state.selectedWindow - 1];
|
||||
is(selectedWindow.extData && selectedWindow.extData[uniqKey], uniqVal,
|
||||
"selectedWindow is window_B");
|
||||
|
||||
// Now minimize window_B. The selected window shouldn't have the secret data
|
||||
window_B.minimize();
|
||||
waitForFocus(function() {
|
||||
// Add identifying information to window_B
|
||||
ss.setWindowValue(window_B, uniqKey, uniqVal);
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
let selectedWindow = state.windows[state.selectedWindow - 1];
|
||||
is(selectedWindow.extData && selectedWindow.extData[uniqKey], uniqVal,
|
||||
"selectedWindow is window_B");
|
||||
state = JSON.parse(ss.getBrowserState());
|
||||
selectedWindow = state.windows[state.selectedWindow - 1];
|
||||
ok(!selectedWindow.extData || !selectedWindow.extData[uniqKey],
|
||||
"selectedWindow is not window_B after minimizing it");
|
||||
|
||||
// Now minimize window_B. The selected window shouldn't have the secret data
|
||||
window_B.minimize();
|
||||
waitForFocus(function() {
|
||||
state = JSON.parse(ss.getBrowserState());
|
||||
selectedWindow = state.windows[state.selectedWindow - 1];
|
||||
ok(!selectedWindow.extData || !selectedWindow.extData[uniqKey],
|
||||
"selectedWindow is not window_B after minimizing it");
|
||||
// Now minimize the last open window (assumes no other tests left windows open)
|
||||
window.minimize();
|
||||
state = JSON.parse(ss.getBrowserState());
|
||||
is(state.selectedWindow, 0,
|
||||
"selectedWindow should be 0 when all windows are minimized");
|
||||
|
||||
// Now minimize the last open window (assumes no other tests left windows open)
|
||||
window.minimize();
|
||||
state = JSON.parse(ss.getBrowserState());
|
||||
is(state.selectedWindow, 0,
|
||||
"selectedWindow should be 0 when all windows are minimized");
|
||||
|
||||
// Cleanup
|
||||
window.restore();
|
||||
window_B.close();
|
||||
finish();
|
||||
});
|
||||
}, window_B);
|
||||
}, false);
|
||||
// Cleanup
|
||||
window.restore();
|
||||
window_B.close();
|
||||
finish();
|
||||
});
|
||||
}, window_B);
|
||||
});
|
||||
}
|
||||
|
@ -174,23 +174,7 @@ function forceWriteState(aCallback) {
|
||||
}
|
||||
|
||||
function testOnWindow(aIsPrivate, aCallback) {
|
||||
let win = OpenBrowserWindow({private: aIsPrivate});
|
||||
let gotLoad = false;
|
||||
let gotActivate = false;
|
||||
win.addEventListener("activate", function onActivate() {
|
||||
win.removeEventListener("activate", onActivate, false);
|
||||
gotActivate = true;
|
||||
if (gotLoad) {
|
||||
executeSoon(function() { aCallback(win) });
|
||||
}
|
||||
}, false);
|
||||
win.addEventListener("load", function onLoad() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
gotLoad = true;
|
||||
if (gotActivate) {
|
||||
executeSoon(function() { aCallback(win) });
|
||||
}
|
||||
}, false);
|
||||
whenNewWindowLoaded({private: aIsPrivate}, aCallback);
|
||||
}
|
||||
|
||||
function waitForTabLoad(aWin, aURL, aCallback) {
|
||||
|
@ -78,9 +78,9 @@ function testWriteNoBackup() {
|
||||
let array = yield OS.File.read(path);
|
||||
gSSData = gDecoder.decode(array);
|
||||
|
||||
// Manually trigger _SessionFile.createBackupCopy since the backup once
|
||||
// Manually trigger _SessionFile.moveToBackupPath since the backup once
|
||||
// promise is already resolved and backup would not be triggered again.
|
||||
yield _SessionFile.createBackupCopy();
|
||||
yield _SessionFile.moveToBackupPath();
|
||||
|
||||
nextTest(testWriteBackup);
|
||||
}
|
||||
@ -140,4 +140,4 @@ function testNoWriteBackup() {
|
||||
is(ssBakData, gSSBakData, "sessionstore.bak is unchanged.");
|
||||
|
||||
executeSoon(finish);
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,11 @@ function test() {
|
||||
function runTests() {
|
||||
// Open a new window.
|
||||
let win = OpenBrowserWindow();
|
||||
yield whenWindowLoaded(win);
|
||||
yield whenDelayedStartupFinished(win, next);
|
||||
|
||||
// Load some URL in the current tab.
|
||||
win.gBrowser.selectedBrowser.loadURI("about:robots");
|
||||
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY;
|
||||
win.gBrowser.selectedBrowser.loadURIWithFlags("about:robots", flags);
|
||||
yield whenBrowserLoaded(win.gBrowser.selectedBrowser);
|
||||
|
||||
// Open a second tab and close the first one.
|
||||
|
@ -19,7 +19,7 @@ function runTests() {
|
||||
// because we always collect data for tabs of active windows no matter if
|
||||
// the window is dirty or not.
|
||||
let win = OpenBrowserWindow();
|
||||
yield waitForLoad(win);
|
||||
yield whenDelayedStartupFinished(win, next);
|
||||
|
||||
// Create a tab with some form fields.
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(URL);
|
||||
|
@ -23,7 +23,7 @@ function runTests() {
|
||||
// because we always collect data for tabs of active windows no matter if
|
||||
// the window is dirty or not.
|
||||
let win = OpenBrowserWindow();
|
||||
yield waitForLoad(win);
|
||||
yield whenDelayedStartupFinished(win, next);
|
||||
|
||||
// Create a tab with two history entries.
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
|
@ -13,9 +13,7 @@ function test() {
|
||||
|
||||
// Load a private window, then close it
|
||||
// and verify it doesn't get remembered for restoring
|
||||
var win = OpenBrowserWindow({private: true});
|
||||
|
||||
whenWindowLoaded(win, function onload() {
|
||||
whenNewWindowLoaded({private: true}, function (win) {
|
||||
info("The private window got loaded");
|
||||
win.addEventListener("SSWindowClosing", function onclosing() {
|
||||
win.removeEventListener("SSWindowClosing", onclosing, false);
|
||||
|
@ -289,39 +289,34 @@ function closeAllButPrimaryWindow() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When opening a new window it is not sufficient to wait for its load event.
|
||||
* We need to use whenDelayedStartupFinshed() here as the browser window's
|
||||
* delayedStartup() routine is executed one tick after the window's load event
|
||||
* has been dispatched. browser-delayed-startup-finished might be deferred even
|
||||
* further if parts of the window's initialization process take more time than
|
||||
* expected (e.g. reading a big session state from disk).
|
||||
*/
|
||||
function whenNewWindowLoaded(aOptions, aCallback) {
|
||||
let win = OpenBrowserWindow(aOptions);
|
||||
let gotLoad = false;
|
||||
let gotActivate = (Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager).activeWindow == win);
|
||||
|
||||
function maybeRunCallback() {
|
||||
if (gotLoad && gotActivate) {
|
||||
win.BrowserChromeTest.runWhenReady(function() {
|
||||
executeSoon(function() { aCallback(win); });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!gotActivate) {
|
||||
win.addEventListener("activate", function onActivate() {
|
||||
info("Got activate.");
|
||||
win.removeEventListener("activate", onActivate, false);
|
||||
gotActivate = true;
|
||||
maybeRunCallback();
|
||||
}, false);
|
||||
} else {
|
||||
info("Was activated.");
|
||||
}
|
||||
|
||||
win.addEventListener("load", function onLoad() {
|
||||
info("Got load");
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
gotLoad = true;
|
||||
maybeRunCallback();
|
||||
}, false);
|
||||
whenDelayedStartupFinished(win, () => aCallback(win));
|
||||
return win;
|
||||
}
|
||||
|
||||
/**
|
||||
* This waits for the browser-delayed-startup-finished notification of a given
|
||||
* window. It indicates that the windows has loaded completely and is ready to
|
||||
* be used for testing.
|
||||
*/
|
||||
function whenDelayedStartupFinished(aWindow, aCallback) {
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic) {
|
||||
if (aWindow == aSubject) {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
executeSoon(aCallback);
|
||||
}
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The test runner that controls the execution flow of our tests.
|
||||
*/
|
||||
|
@ -19,7 +19,7 @@ function pathBackup(ext) {
|
||||
|
||||
// Ensure that things proceed smoothly if there is no file to back up
|
||||
add_task(function test_nothing_to_backup() {
|
||||
yield _SessionFile.createUpgradeBackupCopy("");
|
||||
yield _SessionFile.createBackupCopy("");
|
||||
});
|
||||
|
||||
// Create a file, back it up, remove it
|
||||
@ -29,14 +29,14 @@ add_task(function test_do_backup() {
|
||||
yield OS.File.writeAtomic(pathStore, content, {tmpPath: pathStore + ".tmp"});
|
||||
|
||||
do_print("Ensuring that the backup is created");
|
||||
yield _SessionFile.createUpgradeBackupCopy(ext);
|
||||
yield _SessionFile.createBackupCopy(ext);
|
||||
do_check_true((yield OS.File.exists(pathBackup(ext))));
|
||||
|
||||
let data = yield OS.File.read(pathBackup(ext));
|
||||
do_check_eq((new TextDecoder()).decode(data), content);
|
||||
|
||||
do_print("Ensuring that we can remove the backup");
|
||||
yield _SessionFile.removeUpgradeBackup(ext);
|
||||
yield _SessionFile.removeBackupCopy(ext);
|
||||
do_check_false((yield OS.File.exists(pathBackup(ext))));
|
||||
});
|
||||
|
||||
|
@ -1,17 +1,17 @@
|
||||
[
|
||||
{
|
||||
"clang_version": "r170890"
|
||||
"clang_version": "r185949"
|
||||
},
|
||||
{
|
||||
"filename": "setup.sh",
|
||||
"algorithm": "sha512",
|
||||
"size": 47,
|
||||
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
|
||||
"size": 47
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"filename": "clang.tar.bz2",
|
||||
"size": 72573411,
|
||||
"digest": "491753968f34d1bd3c58280688349499a92f31a118eb6f28e86746be62615004370394b8e1b10d48dc3fba4bc6d4fbb4ce6c7dbc4fadb39447de9aa55573c58e",
|
||||
"algorithm": "sha512",
|
||||
"digest": "0bcfc19f05cc0f042befb3823c7ecce9ba411b152921aa29e97e7adc846e0258fd7da521b1620cb1e61a19d2fcac9b60e6d613c922b6c153e01b9b0766651d09",
|
||||
"size": 62708281
|
||||
"filename": "clang.tar.bz2"
|
||||
}
|
||||
]
|
||||
|
@ -1,17 +1,17 @@
|
||||
[
|
||||
{
|
||||
"clang_version": "r170890"
|
||||
},
|
||||
"clang_version": "r185949"
|
||||
},
|
||||
{
|
||||
"filename": "setup.sh",
|
||||
"algorithm": "sha512",
|
||||
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
|
||||
"size": 47
|
||||
},
|
||||
"size": 47,
|
||||
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"filename": "clang.tar.bz2",
|
||||
"algorithm": "sha512",
|
||||
"digest": "e14ccefd965372a57c540647b2b99e21a4aa82f81a8b9a9e18dac7cba4c3436181bef0dfab8c51bcb5c343f504a693fdcfbe7d609f10291b5dd65ab059979d29",
|
||||
"size": 63034761
|
||||
"size": 73050713,
|
||||
"digest": "2c5c26a44402f974c2a4ccffb07ea1ac2d01d84dc3e4281fef6e047a62606811a16534d034477dfd9be055a07d931b17ca4e883c8edcd1f8d3a8c91b150e2288",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2"
|
||||
}
|
||||
]
|
||||
|
@ -1,17 +1,17 @@
|
||||
[
|
||||
{
|
||||
"clang_version": "r170890"
|
||||
},
|
||||
"clang_version": "r185949"
|
||||
},
|
||||
{
|
||||
"size": 47,
|
||||
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
|
||||
"algorithm": "sha512",
|
||||
"size": 47,
|
||||
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
},
|
||||
{
|
||||
"size": 56126352,
|
||||
"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
|
||||
"algorithm": "sha512",
|
||||
"size": 61779086,
|
||||
"digest": "b2f2861da7583e859b4fb40e1304dd284df02466c909893684341b16e2f58c4c100891504938cf62f26ac82254b9e87135ba98f8196dd26e9b58d3242f1cf811",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2"
|
||||
}
|
||||
]
|
||||
|
@ -69,7 +69,7 @@ gcli.addCommand({
|
||||
throw gcli.lookup("profilerAlreadyStarted2");
|
||||
|
||||
panel.toggleRecording();
|
||||
return gcli.lookup("profilerStarted");
|
||||
return gcli.lookup("profilerStarted2");
|
||||
}
|
||||
|
||||
return gDevTools.showToolbox(context.environment.target, "jsprofiler")
|
||||
|
@ -48,7 +48,7 @@ function testProfilerStart() {
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
cmd("profiler start", gcli.lookup("profilerStarted"));
|
||||
cmd("profiler start", gcli.lookup("profilerStarted2"));
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
@ -1474,7 +1474,9 @@ let SyntaxTreeVisitor = {
|
||||
aCallbacks.onArrayExpression(aNode);
|
||||
}
|
||||
for (let element of aNode.elements) {
|
||||
if (element) {
|
||||
// TODO: remove the typeof check when support for SpreadExpression is
|
||||
// added (bug 890913).
|
||||
if (element && typeof this[element.type] == "function") {
|
||||
this[element.type](element, aNode, aCallbacks);
|
||||
}
|
||||
}
|
||||
|
@ -1251,9 +1251,9 @@ profilerNotFound=Profile not found
|
||||
# start the profiler.
|
||||
profilerNotStarted3=Profiler has not been started yet. Use 'profile start' to start profiling
|
||||
|
||||
# LOCALIZATION NOTE (profilerStarted) A very short string that indicates that
|
||||
# LOCALIZATION NOTE (profilerStarted2) A very short string that indicates that
|
||||
# we have started recording.
|
||||
profilerStarted=Recording...
|
||||
profilerStarted2=Recording…
|
||||
|
||||
# LOCALIZATION NOTE (profilerNotReady) A message that is displayed whenever
|
||||
# an operation cannot be completed because the profiler has not been opened yet.
|
||||
|
11
build/unix/build-clang/clang-trunk.json
Normal file
11
build/unix/build-clang/clang-trunk.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"llvm_revision": "185949",
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
|
||||
"patches": {
|
||||
"macosx64": ["llvm-debug-frame.patch"],
|
||||
"linux64": ["llvm-debug-frame.patch", "no-sse-on-linux.patch"],
|
||||
"linux32": ["llvm-debug-frame.patch", "no-sse-on-linux.patch"]
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIAudioManager.h"
|
||||
#include "nsIDOMIccInfo.h"
|
||||
#include "nsIIccProvider.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsISettingsService.h"
|
||||
#include "nsITelephonyProvider.h"
|
||||
@ -634,12 +636,12 @@ BluetoothHfpManager::HandleVoiceConnectionChanged()
|
||||
void
|
||||
BluetoothHfpManager::HandleIccInfoChanged()
|
||||
{
|
||||
nsCOMPtr<nsIMobileConnectionProvider> connection =
|
||||
nsCOMPtr<nsIIccProvider> icc =
|
||||
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
|
||||
NS_ENSURE_TRUE_VOID(connection);
|
||||
NS_ENSURE_TRUE_VOID(icc);
|
||||
|
||||
nsIDOMMozMobileICCInfo* iccInfo;
|
||||
connection->GetIccInfo(&iccInfo);
|
||||
nsIDOMMozIccInfo* iccInfo;
|
||||
icc->GetIccInfo(&iccInfo);
|
||||
NS_ENSURE_TRUE_VOID(iccInfo);
|
||||
iccInfo->GetMsisdn(mMsisdn);
|
||||
}
|
||||
|
@ -121,4 +121,18 @@ CameraPreviewMediaStream::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Imag
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraPreviewMediaStream::ClearCurrentFrame()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
for (uint32_t i = 0; i < mVideoOutputs.Length(); ++i) {
|
||||
VideoFrameContainer* output = mVideoOutputs[i];
|
||||
output->ClearCurrentFrame();
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(output, &VideoFrameContainer::Invalidate);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
|
||||
// Call these on any thread.
|
||||
void SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage);
|
||||
void ClearCurrentFrame();
|
||||
|
||||
void SetFrameCallback(CameraPreviewFrameCallback* aCallback) {
|
||||
mFrameCallback = aCallback;
|
||||
|
@ -287,6 +287,8 @@ DOMCameraPreview::Stopped(bool aForced)
|
||||
return;
|
||||
}
|
||||
|
||||
mInput->ClearCurrentFrame();
|
||||
|
||||
DOM_CAMERA_LOGI("Dispatching preview stream stopped\n");
|
||||
nsCOMPtr<nsIRunnable> stopped = new PreviewControl(this, PreviewControl::STOPPED);
|
||||
nsresult rv = NS_DispatchToMainThread(stopped);
|
||||
|
@ -7,6 +7,7 @@
|
||||
XPIDL_SOURCES += [
|
||||
'SimToolKit.idl',
|
||||
'nsIDOMIccCardLockErrorEvent.idl',
|
||||
'nsIDOMIccInfo.idl',
|
||||
'nsIDOMIccManager.idl',
|
||||
'nsIIccProvider.idl',
|
||||
'nsINavigatorIccManager.idl',
|
||||
|
45
dom/icc/interfaces/nsIDOMIccInfo.idl
Normal file
45
dom/icc/interfaces/nsIDOMIccInfo.idl
Normal file
@ -0,0 +1,45 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(a45c0fe0-c911-11e2-8b8b-0800200c9a66)]
|
||||
interface nsIDOMMozIccInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
* Integrated Circuit Card Identifier.
|
||||
*/
|
||||
readonly attribute DOMString iccid;
|
||||
|
||||
/**
|
||||
* Mobile Country Code (MCC) of the subscriber's home network.
|
||||
*/
|
||||
readonly attribute DOMString mcc;
|
||||
|
||||
/**
|
||||
* Mobile Network Code (MNC) of the subscriber's home network.
|
||||
*/
|
||||
readonly attribute DOMString mnc;
|
||||
|
||||
/**
|
||||
* Service Provider Name (SPN) of the subscriber's home network.
|
||||
*/
|
||||
readonly attribute DOMString spn;
|
||||
|
||||
/**
|
||||
* Network name must be a part of displayed carrier name.
|
||||
*/
|
||||
readonly attribute boolean isDisplayNetworkNameRequired;
|
||||
|
||||
/**
|
||||
* Service provider name must be a part of displayed carrier name.
|
||||
*/
|
||||
readonly attribute boolean isDisplaySpnRequired;
|
||||
|
||||
/**
|
||||
* Mobile Station ISDN Number (MSISDN) of the subscriber's, aka
|
||||
* his phone number.
|
||||
*/
|
||||
readonly attribute DOMString msisdn;
|
||||
};
|
@ -5,11 +5,12 @@
|
||||
#include "nsIDOMEventTarget.idl"
|
||||
#include "SimToolKit.idl"
|
||||
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIDOMDOMRequest;
|
||||
interface nsIDOMContact;
|
||||
interface nsIDOMDOMRequest;
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIDOMMozIccInfo;
|
||||
|
||||
[scriptable, builtinclass, uuid(5f405112-4da9-4d4d-942c-4da3cb7928e1)]
|
||||
[scriptable, builtinclass, uuid(d362bf60-c910-11e2-8b8b-0800200c9a66)]
|
||||
interface nsIDOMMozIccManager : nsIDOMEventTarget
|
||||
{
|
||||
/**
|
||||
@ -275,6 +276,19 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval onstksessionend;
|
||||
|
||||
// UICC Card Information.
|
||||
|
||||
/**
|
||||
* Information stored in the device's ICC card.
|
||||
*/
|
||||
readonly attribute nsIDOMMozIccInfo iccInfo;
|
||||
|
||||
/**
|
||||
* The 'iccinfochange' event is notified whenever the icc info object
|
||||
* changes.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval oniccinfochange;
|
||||
|
||||
// UICC Card State.
|
||||
|
||||
/**
|
||||
|
@ -4,11 +4,12 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMWindow;
|
||||
interface nsIDOMDOMRequest;
|
||||
interface nsIDOMContact;
|
||||
interface nsIDOMDOMRequest;
|
||||
interface nsIDOMMozIccInfo;
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, uuid(5902d9b0-c2be-11e2-8b8b-0800200c9a66)]
|
||||
[scriptable, uuid(82d25440-c913-11e2-8b8b-0800200c9a66)]
|
||||
interface nsIIccListener : nsISupports
|
||||
{
|
||||
void notifyStkCommand(in DOMString aMessage);
|
||||
@ -16,12 +17,13 @@ interface nsIIccListener : nsISupports
|
||||
void notifyIccCardLockError(in DOMString lockType,
|
||||
in unsigned long retryCount);
|
||||
void notifyCardStateChanged();
|
||||
void notifyIccInfoChanged();
|
||||
};
|
||||
|
||||
/**
|
||||
* XPCOM component (in the content process) that provides the ICC information.
|
||||
*/
|
||||
[scriptable, uuid(7131dfbe-9a2c-434d-b6b8-3eebf491ce1a)]
|
||||
[scriptable, uuid(52fa6780-c913-11e2-8b8b-0800200c9a66)]
|
||||
interface nsIIccProvider : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -32,6 +34,11 @@ interface nsIIccProvider : nsISupports
|
||||
void registerIccMsg(in nsIIccListener listener);
|
||||
void unregisterIccMsg(in nsIIccListener listener);
|
||||
|
||||
/**
|
||||
* UICC Information
|
||||
*/
|
||||
readonly attribute nsIDOMMozIccInfo iccInfo;
|
||||
|
||||
/**
|
||||
* Card State
|
||||
*/
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsIDOMIccCardLockErrorEvent.h"
|
||||
#include "nsIDOMIccInfo.h"
|
||||
#include "GeneratedEvents.h"
|
||||
#include "IccManager.h"
|
||||
#include "SimToolKit.h"
|
||||
@ -129,6 +130,18 @@ IccManager::SendStkEventDownload(const JS::Value& aEvent)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IccManager::GetIccInfo(nsIDOMMozIccInfo** aIccInfo)
|
||||
{
|
||||
*aIccInfo = nullptr;
|
||||
|
||||
if (!mProvider) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return mProvider->GetIccInfo(aIccInfo);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IccManager::GetCardState(nsAString& cardState)
|
||||
{
|
||||
@ -237,6 +250,7 @@ NS_IMPL_EVENT_HANDLER(IccManager, stkcommand)
|
||||
NS_IMPL_EVENT_HANDLER(IccManager, stksessionend)
|
||||
NS_IMPL_EVENT_HANDLER(IccManager, icccardlockerror)
|
||||
NS_IMPL_EVENT_HANDLER(IccManager, cardstatechange)
|
||||
NS_IMPL_EVENT_HANDLER(IccManager, iccinfochange)
|
||||
|
||||
// nsIIccListener
|
||||
|
||||
@ -274,4 +288,10 @@ NS_IMETHODIMP
|
||||
IccManager::NotifyCardStateChanged()
|
||||
{
|
||||
return DispatchTrustedEvent(NS_LITERAL_STRING("cardstatechange"));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IccManager::NotifyIccInfoChanged()
|
||||
{
|
||||
return DispatchTrustedEvent(NS_LITERAL_STRING("iccinfochange"));
|
||||
}
|
@ -5,9 +5,9 @@ MARIONETTE_TIMEOUT = 30000;
|
||||
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
let connection = navigator.mozMobileConnection;
|
||||
ok(connection instanceof MozMobileConnection,
|
||||
"connection is instanceof " + connection.constructor);
|
||||
let icc = navigator.mozIccManager;
|
||||
ok(icc instanceof MozIccManager,
|
||||
"icc is instanceof " + icc.constructor);
|
||||
|
||||
let emulatorCmdPendingCount = 0;
|
||||
function sendEmulatorCommand(cmd, callback) {
|
||||
@ -28,8 +28,8 @@ function setEmulatorMccMnc(mcc, mnc) {
|
||||
}
|
||||
|
||||
function waitForIccInfoChange(callback) {
|
||||
connection.addEventListener("iccinfochange", function handler() {
|
||||
connection.removeEventListener("iccinfochange", handler);
|
||||
icc.addEventListener("iccinfochange", function handler() {
|
||||
icc.removeEventListener("iccinfochange", handler);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
@ -39,18 +39,20 @@ function finalize() {
|
||||
finish();
|
||||
}
|
||||
|
||||
let iccInfo = icc.iccInfo;
|
||||
|
||||
// The emulator's hard coded iccid value.
|
||||
// See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299.
|
||||
is(connection.iccInfo.iccid, 89014103211118510720);
|
||||
is(iccInfo.iccid, 89014103211118510720);
|
||||
|
||||
// The emulator's hard coded mcc and mnc codes.
|
||||
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465.
|
||||
is(connection.iccInfo.mcc, 310);
|
||||
is(connection.iccInfo.mnc, 260);
|
||||
is(connection.iccInfo.spn, "Android");
|
||||
is(iccInfo.mcc, 310);
|
||||
is(iccInfo.mnc, 260);
|
||||
is(iccInfo.spn, "Android");
|
||||
// Phone number is hardcoded in MSISDN
|
||||
// See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io()
|
||||
is(connection.iccInfo.msisdn, "15555215554");
|
||||
is(iccInfo.msisdn, "15555215554");
|
||||
|
||||
// Test display condition change.
|
||||
function testDisplayConditionChange(func, caseArray, oncomplete) {
|
||||
@ -64,9 +66,9 @@ function testDisplayConditionChange(func, caseArray, oncomplete) {
|
||||
function testSPN(mcc, mnc, expectedIsDisplayNetworkNameRequired,
|
||||
expectedIsDisplaySpnRequired, callback) {
|
||||
waitForIccInfoChange(function() {
|
||||
is(connection.iccInfo.isDisplayNetworkNameRequired,
|
||||
is(iccInfo.isDisplayNetworkNameRequired,
|
||||
expectedIsDisplayNetworkNameRequired);
|
||||
is(connection.iccInfo.isDisplaySpnRequired,
|
||||
is(iccInfo.isDisplaySpnRequired,
|
||||
expectedIsDisplaySpnRequired);
|
||||
// operatorchange will be ignored if we send commands too soon.
|
||||
window.setTimeout(callback, 100);
|
@ -6,13 +6,12 @@
|
||||
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIDOMDOMRequest;
|
||||
interface nsIDOMMozMobileICCInfo;
|
||||
interface nsIDOMMozMobileConnectionInfo;
|
||||
interface nsIDOMMozMobileNetworkInfo;
|
||||
interface nsIDOMMozMobileCellInfo;
|
||||
interface nsIDOMMozMobileCFInfo;
|
||||
|
||||
[scriptable, builtinclass, uuid(dc010230-c2bc-11e2-8b8b-0800200c9a66)]
|
||||
[scriptable, builtinclass, uuid(fd26e2e0-c910-11e2-8b8b-0800200c9a66)]
|
||||
interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
||||
{
|
||||
const long ICC_SERVICE_CLASS_VOICE = (1 << 0);
|
||||
@ -55,11 +54,6 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
||||
*/
|
||||
readonly attribute long retryCount;
|
||||
|
||||
/**
|
||||
* Information stored in the device's ICC card.
|
||||
*/
|
||||
readonly attribute nsIDOMMozMobileICCInfo iccInfo;
|
||||
|
||||
/**
|
||||
* Information about the voice connection.
|
||||
*/
|
||||
@ -232,12 +226,6 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
||||
*/
|
||||
nsIDOMDOMRequest getCallWaitingOption();
|
||||
|
||||
/**
|
||||
* The 'iccinfochange' event is notified whenever the icc info object
|
||||
* changes.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval oniccinfochange;
|
||||
|
||||
/**
|
||||
* The 'voicechange' event is notified whenever the voice connection object
|
||||
* changes.
|
||||
@ -380,46 +368,6 @@ interface nsIDOMMozMobileCellInfo: nsISupports
|
||||
readonly attribute unsigned long gsmCellId;
|
||||
};
|
||||
|
||||
[scriptable, uuid(10d5c5a2-d43f-4f94-8657-cf7ccabbab6e)]
|
||||
interface nsIDOMMozMobileICCInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
* Integrated Circuit Card Identifier.
|
||||
*/
|
||||
readonly attribute DOMString iccid;
|
||||
|
||||
/**
|
||||
* Mobile Country Code (MCC) of the subscriber's home network.
|
||||
*/
|
||||
readonly attribute DOMString mcc;
|
||||
|
||||
/**
|
||||
* Mobile Network Code (MNC) of the subscriber's home network.
|
||||
*/
|
||||
readonly attribute DOMString mnc;
|
||||
|
||||
/**
|
||||
* Service Provider Name (SPN) of the subscriber's home network.
|
||||
*/
|
||||
readonly attribute DOMString spn;
|
||||
|
||||
/**
|
||||
* Network name must be a part of displayed carrier name.
|
||||
*/
|
||||
readonly attribute boolean isDisplayNetworkNameRequired;
|
||||
|
||||
/**
|
||||
* Service provider name must be a part of displayed carrier name.
|
||||
*/
|
||||
readonly attribute boolean isDisplaySpnRequired;
|
||||
|
||||
/**
|
||||
* Mobile Station ISDN Number (MSISDN) of the subscriber's, aka
|
||||
* his phone number.
|
||||
*/
|
||||
readonly attribute DOMString msisdn;
|
||||
};
|
||||
|
||||
[scriptable, uuid(d1b35ad8-99aa-47cc-ab49-2e72b00e39df)]
|
||||
interface nsIDOMMozMobileCFInfo : nsISupports
|
||||
{
|
||||
|
@ -4,19 +4,17 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMMozMobileICCInfo;
|
||||
interface nsIDOMDOMRequest;
|
||||
interface nsIDOMMozMobileCFInfo;
|
||||
interface nsIDOMMozMobileConnectionInfo;
|
||||
interface nsIDOMMozMobileNetworkInfo;
|
||||
interface nsIDOMMozMobileCFInfo;
|
||||
interface nsIDOMDOMRequest;
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, uuid(529864f0-c2be-11e2-8b8b-0800200c9a66)]
|
||||
[scriptable, uuid(74361840-c913-11e2-8b8b-0800200c9a66)]
|
||||
interface nsIMobileConnectionListener : nsISupports
|
||||
{
|
||||
void notifyVoiceChanged();
|
||||
void notifyDataChanged();
|
||||
void notifyIccInfoChanged();
|
||||
void notifyUssdReceived(in DOMString message,
|
||||
in boolean sessionEnded);
|
||||
void notifyDataError(in DOMString message);
|
||||
@ -32,7 +30,7 @@ interface nsIMobileConnectionListener : nsISupports
|
||||
* XPCOM component (in the content process) that provides the mobile
|
||||
* network information.
|
||||
*/
|
||||
[scriptable, uuid(66e7ac90-c2be-11e2-8b8b-0800200c9a66)]
|
||||
[scriptable, uuid(477d93f0-c913-11e2-8b8b-0800200c9a66)]
|
||||
interface nsIMobileConnectionProvider : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -44,7 +42,6 @@ interface nsIMobileConnectionProvider : nsISupports
|
||||
void unregisterMobileConnectionMsg(in nsIMobileConnectionListener listener);
|
||||
|
||||
readonly attribute long retryCount;
|
||||
readonly attribute nsIDOMMozMobileICCInfo iccInfo;
|
||||
readonly attribute nsIDOMMozMobileConnectionInfo voiceConnectionInfo;
|
||||
readonly attribute nsIDOMMozMobileConnectionInfo dataConnectionInfo;
|
||||
readonly attribute DOMString networkSelectionMode;
|
||||
|
@ -67,7 +67,6 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
NS_IMPL_ADDREF_INHERITED(MobileConnection, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(MobileConnection, nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, iccinfochange)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, voicechange)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, datachange)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, ussdreceived)
|
||||
@ -172,17 +171,6 @@ MobileConnection::GetRetryCount(int32_t* retryCount)
|
||||
return mProvider->GetRetryCount(retryCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileConnection::GetIccInfo(nsIDOMMozMobileICCInfo** aIccInfo)
|
||||
{
|
||||
*aIccInfo = nullptr;
|
||||
|
||||
if (!mProvider || !CheckPermission("mobileconnection")) {
|
||||
return NS_OK;
|
||||
}
|
||||
return mProvider->GetIccInfo(aIccInfo);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileConnection::GetVoice(nsIDOMMozMobileConnectionInfo** voice)
|
||||
{
|
||||
@ -416,16 +404,6 @@ MobileConnection::NotifyDataChanged()
|
||||
return DispatchTrustedEvent(NS_LITERAL_STRING("datachange"));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileConnection::NotifyIccInfoChanged()
|
||||
{
|
||||
if (!CheckPermission("mobileconnection")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DispatchTrustedEvent(NS_LITERAL_STRING("iccinfochange"));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileConnection::NotifyUssdReceived(const nsAString& aMessage,
|
||||
bool aSessionEnded)
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsINetworkManager.h"
|
||||
#include "nsIRadioInterfaceLayer.h"
|
||||
#include "nsIDOMIccInfo.h"
|
||||
#include "nsIDOMMobileConnection.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
@ -422,7 +423,7 @@ GonkGPSGeolocationProvider::RequestSetID(uint32_t flags)
|
||||
}
|
||||
|
||||
if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) {
|
||||
nsCOMPtr<nsIDOMMozMobileICCInfo> iccInfo;
|
||||
nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
|
||||
rilCtx->GetIccInfo(getter_AddRefs(iccInfo));
|
||||
if (iccInfo) {
|
||||
type = AGPS_SETID_TYPE_MSISDN;
|
||||
@ -453,7 +454,7 @@ GonkGPSGeolocationProvider::SetReferenceLocation()
|
||||
location.type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
|
||||
|
||||
if (rilCtx) {
|
||||
nsCOMPtr<nsIDOMMozMobileICCInfo> iccInfo;
|
||||
nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
|
||||
rilCtx->GetIccInfo(getter_AddRefs(iccInfo));
|
||||
if (iccInfo) {
|
||||
nsresult result;
|
||||
|
@ -45,8 +45,8 @@ if (DEBUG) {
|
||||
|
||||
const RILCONTENTHELPER_CID =
|
||||
Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
|
||||
const MOBILEICCINFO_CID =
|
||||
Components.ID("{8649c12f-f8f4-4664-bbdd-7d115c23e2a7}");
|
||||
const ICCINFO_CID =
|
||||
Components.ID("{fab2c0f0-d73a-11e2-8b8b-0800200c9a66}");
|
||||
const MOBILECONNECTIONINFO_CID =
|
||||
Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}");
|
||||
const MOBILENETWORKINFO_CID =
|
||||
@ -135,18 +135,18 @@ MobileIccCardLockRetryCount.prototype = {
|
||||
success: 'r'}
|
||||
};
|
||||
|
||||
function MobileICCInfo() {}
|
||||
MobileICCInfo.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileICCInfo]),
|
||||
classID: MOBILEICCINFO_CID,
|
||||
function IccInfo() {}
|
||||
IccInfo.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozIccInfo]),
|
||||
classID: ICCINFO_CID,
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: MOBILEICCINFO_CID,
|
||||
classDescription: "MobileICCInfo",
|
||||
classID: ICCINFO_CID,
|
||||
classDescription: "IccInfo",
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
interfaces: [Ci.nsIDOMMozMobileICCInfo]
|
||||
interfaces: [Ci.nsIDOMMozIccInfo]
|
||||
}),
|
||||
|
||||
// nsIDOMMozMobileICCInfo
|
||||
// nsIDOMMozIccInfo
|
||||
|
||||
iccid: null,
|
||||
mcc: null,
|
||||
@ -381,7 +381,7 @@ function RILContentHelper() {
|
||||
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
|
||||
retryCount: 0,
|
||||
networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN,
|
||||
iccInfo: new MobileICCInfo(),
|
||||
iccInfo: new IccInfo(),
|
||||
voiceConnectionInfo: new MobileConnectionInfo(),
|
||||
dataConnectionInfo: new MobileConnectionInfo()
|
||||
};
|
||||
@ -1337,8 +1337,7 @@ RILContentHelper.prototype = {
|
||||
}
|
||||
case "RIL:IccInfoChanged":
|
||||
this.updateInfo(msg.json.data, this.rilContext.iccInfo);
|
||||
this._deliverEvent("_mobileConnectionListeners",
|
||||
"notifyIccInfoChanged", null);
|
||||
this._deliverEvent("_iccListeners", "notifyIccInfoChanged", null);
|
||||
break;
|
||||
case "RIL:VoiceInfoChanged":
|
||||
this.updateConnectionInfo(msg.json.data,
|
||||
|
@ -610,12 +610,20 @@ XPCOMUtils.defineLazyGetter(RadioInterfaceLayer.prototype,
|
||||
function RadioInterface(options) {
|
||||
this.clientId = options.clientId;
|
||||
|
||||
this.dataCallSettings = {};
|
||||
this.dataNetworkInterface = new RILNetworkInterface(this, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE);
|
||||
this.dataCallSettingsMMS = {};
|
||||
this.mmsNetworkInterface = new RILNetworkInterface(this, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS);
|
||||
this.dataCallSettingsSUPL = {};
|
||||
this.suplNetworkInterface = new RILNetworkInterface(this, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL);
|
||||
this.dataCallSettings = {
|
||||
oldEnabled: false,
|
||||
enabled: false,
|
||||
roamingEnabled: false
|
||||
};
|
||||
|
||||
// apnSettings is used to keep all APN settings.
|
||||
// byApn[] makes it easier to get the APN settings via APN, user
|
||||
// name, and password.
|
||||
// byType[] makes it easier to get the APN settings via APN types.
|
||||
this.apnSettings = {
|
||||
byType: {},
|
||||
byAPN: {}
|
||||
};
|
||||
|
||||
if (DEBUG) this.debug("Starting RIL Worker[" + this.clientId + "]");
|
||||
this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
|
||||
@ -677,39 +685,9 @@ function RadioInterface(options) {
|
||||
lock.get("ril.radio.preferredNetworkType", this);
|
||||
|
||||
// Read the APN data from the settings DB.
|
||||
lock.get("ril.data.apn", this);
|
||||
lock.get("ril.data.user", this);
|
||||
lock.get("ril.data.passwd", this);
|
||||
lock.get("ril.data.authtype", this);
|
||||
lock.get("ril.data.httpProxyHost", this);
|
||||
lock.get("ril.data.httpProxyPort", this);
|
||||
lock.get("ril.data.roaming_enabled", this);
|
||||
lock.get("ril.data.enabled", this);
|
||||
this._dataCallSettingsToRead = ["ril.data.enabled",
|
||||
"ril.data.roaming_enabled",
|
||||
"ril.data.apn",
|
||||
"ril.data.user",
|
||||
"ril.data.passwd",
|
||||
"ril.data.authtype",
|
||||
"ril.data.httpProxyHost",
|
||||
"ril.data.httpProxyPort"];
|
||||
|
||||
// Read secondary APNs from the settings DB.
|
||||
lock.get("ril.mms.apn", this);
|
||||
lock.get("ril.mms.user", this);
|
||||
lock.get("ril.mms.passwd", this);
|
||||
lock.get("ril.mms.authtype", this);
|
||||
lock.get("ril.mms.httpProxyHost", this);
|
||||
lock.get("ril.mms.httpProxyPort", this);
|
||||
lock.get("ril.mms.mmsc", this);
|
||||
lock.get("ril.mms.mmsproxy", this);
|
||||
lock.get("ril.mms.mmsport", this);
|
||||
lock.get("ril.supl.apn", this);
|
||||
lock.get("ril.supl.user", this);
|
||||
lock.get("ril.supl.passwd", this);
|
||||
lock.get("ril.supl.authtype", this);
|
||||
lock.get("ril.supl.httpProxyHost", this);
|
||||
lock.get("ril.supl.httpProxyPort", this);
|
||||
lock.get("ril.data.apnSettings", this);
|
||||
|
||||
// Read the 'time.nitz.automatic-update.enabled' setting to see if
|
||||
// we need to adjust the system clock time and time zone by NITZ.
|
||||
@ -1218,8 +1196,12 @@ RadioInterface.prototype = {
|
||||
dataInfo.type = newInfo.type;
|
||||
// For the data connection, the `connected` flag indicates whether
|
||||
// there's an active data call.
|
||||
dataInfo.connected = (this.getDataCallStateByType("default") ==
|
||||
RIL.GECKO_NETWORK_STATE_CONNECTED);
|
||||
let apnSetting = this.apnSettings.byType.default;
|
||||
dataInfo.connected = false;
|
||||
if (apnSetting) {
|
||||
dataInfo.connected = (this.getDataCallStateByType("default") ==
|
||||
RIL.GECKO_NETWORK_STATE_CONNECTED);
|
||||
}
|
||||
|
||||
// Make sure we also reset the operator and signal strength information
|
||||
// if we drop off the network.
|
||||
@ -1248,9 +1230,13 @@ RadioInterface.prototype = {
|
||||
*/
|
||||
handleDataCallError: function handleDataCallError(message) {
|
||||
// Notify data call error only for data APN
|
||||
if (message.apn == this.dataCallSettings.apn) {
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:DataError",
|
||||
this.clientId, message);
|
||||
if (this.apnSettings.byType.default) {
|
||||
let apnSetting = this.apnSettings.byType.default;
|
||||
if (message.apn == apnSetting.apn &&
|
||||
apnSetting.iface.inConnectedTypes("default")) {
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:DataError",
|
||||
this.clientId, message);
|
||||
}
|
||||
}
|
||||
|
||||
this._deliverDataCallCallback("dataCallError", [message]);
|
||||
@ -1430,11 +1416,85 @@ RadioInterface.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function will do the following steps:
|
||||
* 1. Clear the old APN settings.
|
||||
* 2. Combine APN, user name, and password as the key of byAPN{} and store
|
||||
* corresponding APN setting into byApn{}, which makes it easiler to get
|
||||
* the APN setting.
|
||||
* 3. Use APN type as the index of byType{} and store the link of
|
||||
* corresponding APN setting into byType{}, which makes it easier to get
|
||||
* the APN setting via APN types.
|
||||
*/
|
||||
updateApnSettings: function updateApnSettings(allApnSettings) {
|
||||
// TODO: Support multi-SIM, bug 799023.
|
||||
let simNumber = 1;
|
||||
for (let simId = 0; simId < simNumber; simId++) {
|
||||
let thisSimApnSettings = allApnSettings[simId];
|
||||
if (!thisSimApnSettings) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear old APN settings.
|
||||
for each (let apnSetting in this.apnSettings.byAPN) {
|
||||
// Clear all connections of this APN settings.
|
||||
for each (let type in apnSetting.types) {
|
||||
if (this.getDataCallStateByType(type) ==
|
||||
RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
this.deactivateDataCallByType(type);
|
||||
}
|
||||
}
|
||||
if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
|
||||
gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
|
||||
}
|
||||
this.unregisterDataCallCallback(apnSetting.iface);
|
||||
delete apnSetting.iface;
|
||||
}
|
||||
this.apnSettings.byAPN = {};
|
||||
this.apnSettings.byType = {};
|
||||
|
||||
// Create new APN settings.
|
||||
for (let apnIndex = 0; thisSimApnSettings[apnIndex]; apnIndex++) {
|
||||
let inputApnSetting = thisSimApnSettings[apnIndex];
|
||||
if (!this.validateApnSetting(inputApnSetting)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Combine APN, user name, and password as the key of byAPN{} to get
|
||||
// the corresponding APN setting.
|
||||
let apnKey = inputApnSetting.apn + (inputApnSetting.user || '') +
|
||||
(inputApnSetting.password || '');
|
||||
if (!this.apnSettings.byAPN[apnKey]) {
|
||||
this.apnSettings.byAPN[apnKey] = {};
|
||||
this.apnSettings.byAPN[apnKey] = inputApnSetting;
|
||||
this.apnSettings.byAPN[apnKey].iface =
|
||||
new RILNetworkInterface(this, this.apnSettings.byAPN[apnKey]);
|
||||
} else {
|
||||
this.apnSettings.byAPN[apnKey].types.push(inputApnSetting.types);
|
||||
}
|
||||
for each (let type in inputApnSetting.types) {
|
||||
this.apnSettings.byType[type] = {};
|
||||
this.apnSettings.byType[type] = this.apnSettings.byAPN[apnKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if we get all necessary APN data.
|
||||
*/
|
||||
validateApnSetting: function validateApnSetting(apnSetting) {
|
||||
return (apnSetting &&
|
||||
apnSetting.apn &&
|
||||
apnSetting.types &&
|
||||
apnSetting.types.length);
|
||||
},
|
||||
|
||||
updateRILNetworkInterface: function updateRILNetworkInterface() {
|
||||
if (this._dataCallSettingsToRead.length) {
|
||||
let apnSetting = this.apnSettings.byType.default;
|
||||
if (!this.validateApnSetting(apnSetting)) {
|
||||
if (DEBUG) {
|
||||
this.debug("We haven't read completely the APN data from the " +
|
||||
"settings DB yet. Wait for that.");
|
||||
this.debug("We haven't gotten completely the APN data.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1453,7 +1513,7 @@ RadioInterface.prototype = {
|
||||
// true and any of the remaining flags change the setting application
|
||||
// should turn this flag to false and then to true in order to reload
|
||||
// the new values and reconnect the data call.
|
||||
if (this._oldRilDataEnabledState == this.dataCallSettings.enabled) {
|
||||
if (this.dataCallSettings.oldEnabled == this.dataCallSettings.enabled) {
|
||||
if (DEBUG) {
|
||||
this.debug("No changes for ril.data.enabled flag. Nothing to do.");
|
||||
}
|
||||
@ -1490,17 +1550,24 @@ RadioInterface.prototype = {
|
||||
let defaultDataCallConnected = defaultDataCallState ==
|
||||
RIL.GECKO_NETWORK_STATE_CONNECTED;
|
||||
if (defaultDataCallConnected &&
|
||||
(!this.dataCallSettings.enabled || wifi_active ||
|
||||
(dataInfo.roaming && !this.dataCallSettings.roaming_enabled))) {
|
||||
(!this.dataCallSettings.enabled ||
|
||||
(dataInfo.roaming && !this.dataCallSettings.roamingEnabled))) {
|
||||
if (DEBUG) this.debug("Data call settings: disconnect data call.");
|
||||
this.deactivateDataCallByType("default");
|
||||
return;
|
||||
}
|
||||
|
||||
if (defaultDataCallConnected && wifi_active) {
|
||||
if (DEBUG) this.debug("Disconnect data call when Wifi is connected.");
|
||||
this.deactivateDataCallByType("default");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dataCallSettings.enabled || defaultDataCallConnected) {
|
||||
if (DEBUG) this.debug("Data call settings: nothing to do.");
|
||||
return;
|
||||
}
|
||||
if (dataInfo.roaming && !this.dataCallSettings.roaming_enabled) {
|
||||
if (dataInfo.roaming && !this.dataCallSettings.roamingEnabled) {
|
||||
if (DEBUG) this.debug("We're roaming, but data roaming is disabled.");
|
||||
return;
|
||||
}
|
||||
@ -1980,15 +2047,22 @@ RadioInterface.prototype = {
|
||||
*/
|
||||
handleDataCallState: function handleDataCallState(datacall) {
|
||||
let data = this.rilContext.data;
|
||||
|
||||
if (datacall.ifname && datacall.apn == this.dataCallSettings.apn) {
|
||||
data.connected = false;
|
||||
if (this.dataNetworkInterface.inConnectedTypes("default") &&
|
||||
datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
data.connected = true;
|
||||
let apnSetting = this.apnSettings.byType.default;
|
||||
let dataCallConnected =
|
||||
(datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED);
|
||||
if (apnSetting && datacall.ifname) {
|
||||
if (dataCallConnected && datacall.apn == apnSetting.apn &&
|
||||
apnSetting.iface.inConnectedTypes("default")) {
|
||||
data.connected = dataCallConnected;
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
||||
this.clientId, data);
|
||||
data.apn = datacall.apn;
|
||||
} else if (!dataCallConnected && datacall.apn == data.apn) {
|
||||
data.connected = dataCallConnected;
|
||||
delete data.apn;
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
||||
this.clientId, data);
|
||||
}
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
||||
this.clientId, data);
|
||||
}
|
||||
|
||||
this._deliverDataCallCallback("dataCallStateChanged",
|
||||
@ -2080,8 +2154,8 @@ RadioInterface.prototype = {
|
||||
}
|
||||
// RIL:IccInfoChanged corresponds to a DOM event that gets fired only
|
||||
// when the MCC or MNC codes have changed.
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:IccInfoChanged",
|
||||
this.clientId, message);
|
||||
gMessageManager.sendIccMessage("RIL:IccInfoChanged",
|
||||
this.clientId, message);
|
||||
|
||||
// Update lastKnownHomeNetwork.
|
||||
if (message.mcc && message.mnc) {
|
||||
@ -2215,9 +2289,11 @@ RadioInterface.prototype = {
|
||||
// Cancel the timer for the call-ring wake lock.
|
||||
this._cancelCallRingWakeLockTimer();
|
||||
// Shutdown all RIL network interfaces
|
||||
this.dataNetworkInterface.shutdown();
|
||||
this.mmsNetworkInterface.shutdown();
|
||||
this.suplNetworkInterface.shutdown();
|
||||
for each (let apnSetting in this.apnSettings.byAPN) {
|
||||
if (apnSetting.iface) {
|
||||
apnSetting.iface.shutdown();
|
||||
}
|
||||
}
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
|
||||
Services.obs.removeObserver(this, kSysClockChangeObserverTopic);
|
||||
@ -2247,12 +2323,10 @@ RadioInterface.prototype = {
|
||||
// the radio power.
|
||||
_changingRadioPower: false,
|
||||
|
||||
// APN data for making data calls.
|
||||
// Data calls setting.
|
||||
dataCallSettings: null,
|
||||
dataCallSettingsMMS: null,
|
||||
dataCallSettingsSUPL: null,
|
||||
_dataCallSettingsToRead: null,
|
||||
_oldRilDataEnabledState: null,
|
||||
|
||||
apnSettings: null,
|
||||
|
||||
// Flag to determine whether to use NITZ. It corresponds to the
|
||||
// 'time.nitz.automatic-update.enabled' setting from the UI.
|
||||
@ -2294,46 +2368,22 @@ RadioInterface.prototype = {
|
||||
this.setPreferredNetworkType(aResult);
|
||||
break;
|
||||
case "ril.data.enabled":
|
||||
this._oldRilDataEnabledState = this.dataCallSettings.enabled;
|
||||
// Fall through.
|
||||
case "ril.data.roaming_enabled":
|
||||
case "ril.data.apn":
|
||||
case "ril.data.user":
|
||||
case "ril.data.passwd":
|
||||
case "ril.data.authtype":
|
||||
case "ril.data.httpProxyHost":
|
||||
case "ril.data.httpProxyPort":
|
||||
let key = aName.slice(9);
|
||||
this.dataCallSettings[key] = aResult;
|
||||
if (DEBUG) {
|
||||
this.debug("'" + aName + "'" + " is now " + this.dataCallSettings[key]);
|
||||
}
|
||||
let index = this._dataCallSettingsToRead.indexOf(aName);
|
||||
if (index != -1) {
|
||||
this._dataCallSettingsToRead.splice(index, 1);
|
||||
}
|
||||
if (DEBUG) this.debug("'ril.data.enabled' is now " + aResult);
|
||||
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
|
||||
this.dataCallSettings.enabled = aResult;
|
||||
this.updateRILNetworkInterface();
|
||||
break;
|
||||
case "ril.mms.apn":
|
||||
case "ril.mms.user":
|
||||
case "ril.mms.passwd":
|
||||
case "ril.mms.authtype":
|
||||
case "ril.mms.httpProxyHost":
|
||||
case "ril.mms.httpProxyPort":
|
||||
case "ril.mms.mmsc":
|
||||
case "ril.mms.mmsproxy":
|
||||
case "ril.mms.mmsport":
|
||||
key = aName.slice(8);
|
||||
this.dataCallSettingsMMS[key] = aResult;
|
||||
case "ril.data.roaming_enabled":
|
||||
if (DEBUG) this.debug("'ril.data.roaming_enabled' is now " + aResult);
|
||||
this.dataCallSettings.roamingEnabled = aResult;
|
||||
this.updateRILNetworkInterface();
|
||||
break;
|
||||
case "ril.supl.apn":
|
||||
case "ril.supl.user":
|
||||
case "ril.supl.passwd":
|
||||
case "ril.supl.authtype":
|
||||
case "ril.supl.httpProxyHost":
|
||||
case "ril.supl.httpProxyPort":
|
||||
key = aName.slice(9);
|
||||
this.dataCallSettingsSUPL[key] = aResult;
|
||||
case "ril.data.apnSettings":
|
||||
if (DEBUG) this.debug("'ril.data.apnSettings' is now " + JSON.stringify(aResult));
|
||||
if (aResult) {
|
||||
this.updateApnSettings(aResult);
|
||||
this.updateRILNetworkInterface();
|
||||
}
|
||||
break;
|
||||
case kTimeNitzAutomaticUpdateEnabled:
|
||||
this._nitzAutomaticUpdateEnabled = aResult;
|
||||
@ -2360,8 +2410,13 @@ RadioInterface.prototype = {
|
||||
this._ensureRadioState();
|
||||
|
||||
// Clean data call setting.
|
||||
this.dataCallSettings = {};
|
||||
this.dataCallSettings.oldEnabled = false;
|
||||
this.dataCallSettings.enabled = false;
|
||||
this.dataCallSettings.roamingEnabled = false;
|
||||
this.apnSettings = {
|
||||
byType: {},
|
||||
byAPN: {},
|
||||
};
|
||||
},
|
||||
|
||||
// nsIRadioWorker
|
||||
@ -3161,32 +3216,27 @@ RadioInterface.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine whether secondary APN goes through default APN.
|
||||
*/
|
||||
usingDefaultAPN: function usingDefaultAPN(apntype) {
|
||||
switch (apntype) {
|
||||
case "mms":
|
||||
return (this.dataCallSettingsMMS.apn == this.dataCallSettings.apn);
|
||||
case "supl":
|
||||
return (this.dataCallSettingsSUPL.apn == this.dataCallSettings.apn);
|
||||
default:
|
||||
return false;
|
||||
setupDataCallByType: function setupDataCallByType(apntype) {
|
||||
let apnSetting = this.apnSettings.byType[apntype];
|
||||
if (!apnSetting) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
setupDataCallBySharedApn: function setupDataCallBySharedApn(apntype) {
|
||||
this.dataNetworkInterface.connect(this.dataCallSettings, apntype);
|
||||
let dataInfo = this.rilContext.data;
|
||||
if (dataInfo.state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED ||
|
||||
dataInfo.type == RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
apnSetting.iface.connect(apntype);
|
||||
// We just call connect() function, so this interface should be in
|
||||
// connecting state. If this interface is already in connected state, we
|
||||
// are sure that this interface have successfully established connection
|
||||
// for other data call types before we call connect() function for current
|
||||
// data call type. In this circumstance, we have to directly update the
|
||||
// necessary data call and interface information to RILContentHelper
|
||||
// and network manager.
|
||||
if (this.dataNetworkInterface.connected) {
|
||||
let dataInfo = this.rilContext.data;
|
||||
// and network manager for current data call type.
|
||||
if (apnSetting.iface.connected) {
|
||||
if (apntype == "default" && !dataInfo.connected) {
|
||||
dataInfo.connected = true;
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
||||
@ -3195,53 +3245,31 @@ RadioInterface.prototype = {
|
||||
|
||||
// Update the interface status via-registration if the interface has
|
||||
// already been registered in the network manager.
|
||||
if (this.dataNetworkInterface.name in gNetworkManager.networkInterfaces) {
|
||||
gNetworkManager.unregisterNetworkInterface(this.dataNetworkInterface);
|
||||
if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
|
||||
gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
|
||||
}
|
||||
gNetworkManager.registerNetworkInterface(this.dataNetworkInterface);
|
||||
gNetworkManager.registerNetworkInterface(apnSetting.iface);
|
||||
|
||||
Services.obs.notifyObservers(this.dataNetworkInterface,
|
||||
Services.obs.notifyObservers(apnSetting.iface,
|
||||
kNetworkInterfaceStateChangedTopic,
|
||||
null);
|
||||
}
|
||||
},
|
||||
|
||||
setupDataCallByType: function setupDataCallByType(apntype) {
|
||||
// If it's a shared apn type then we can only reuse the
|
||||
// dataNetworkInterface in current design.
|
||||
if (this.usingDefaultAPN(apntype) ||
|
||||
(apntype == "default" && this.usingDefaultAPN("mms")) ||
|
||||
(apntype == "default" && this.usingDefaultAPN("supl"))) {
|
||||
this.setupDataCallBySharedApn(apntype);
|
||||
deactivateDataCallByType: function deactivateDataCallByType(apntype) {
|
||||
let apnSetting = this.apnSettings.byType[apntype];
|
||||
if (!apnSetting) {
|
||||
return;
|
||||
}
|
||||
switch (apntype) {
|
||||
case "default":
|
||||
this.dataNetworkInterface.connect(this.dataCallSettings, apntype);
|
||||
break;
|
||||
case "mms":
|
||||
this.mmsNetworkInterface.connect(this.dataCallSettingsMMS, apntype);
|
||||
break;
|
||||
case "supl":
|
||||
this.suplNetworkInterface.connect(this.dataCallSettingsSUPL, apntype);
|
||||
break;
|
||||
default:
|
||||
if (DEBUG) this.debug("Unsupported APN type " + apntype);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
deactivateDataCallBySharedApn: function deactivateDataCallBySharedApn(apntype) {
|
||||
this.dataNetworkInterface.disconnect(apntype);
|
||||
|
||||
apnSetting.iface.disconnect(apntype);
|
||||
// We just call disconnect() function, so this interface should be in
|
||||
// disconnecting state. If this interface is still in connected state, we
|
||||
// are sure that other data call types still need this connection of this
|
||||
// interface. In this circumstance, we have to directly update the
|
||||
// necessary data call and interface information to RILContentHelper
|
||||
// and network manager.
|
||||
if (this.dataNetworkInterface.connectedTypes.length &&
|
||||
this.dataNetworkInterface.connected) {
|
||||
// and network manager for current data call type.
|
||||
if (apnSetting.iface.connectedTypes.length && apnSetting.iface.connected) {
|
||||
let dataInfo = this.rilContext.data;
|
||||
if (apntype == "default" && dataInfo.connected) {
|
||||
dataInfo.connected = false;
|
||||
@ -3251,63 +3279,26 @@ RadioInterface.prototype = {
|
||||
|
||||
// Update the interface status via-registration if the interface has
|
||||
// already been registered in the network manager.
|
||||
if (this.dataNetworkInterface.name in gNetworkManager.networkInterfaces) {
|
||||
gNetworkManager.unregisterNetworkInterface(this.dataNetworkInterface);
|
||||
if (apnSetting.iface.name in gNetworkManager.networkInterfaces) {
|
||||
gNetworkManager.unregisterNetworkInterface(apnSetting.iface);
|
||||
}
|
||||
gNetworkManager.registerNetworkInterface(this.dataNetworkInterface);
|
||||
gNetworkManager.registerNetworkInterface(apnSetting.iface);
|
||||
|
||||
Services.obs.notifyObservers(this.dataNetworkInterface,
|
||||
Services.obs.notifyObservers(apnSetting.iface,
|
||||
kNetworkInterfaceStateChangedTopic,
|
||||
null);
|
||||
}
|
||||
},
|
||||
|
||||
deactivateDataCallByType: function deactivateDataCallByType(apntype) {
|
||||
// If it's a shared apn type then we can only reuse the
|
||||
// dataNetworkInterface in current design.
|
||||
if (this.usingDefaultAPN(apntype) ||
|
||||
(apntype == "default" && this.usingDefaultAPN("mms")) ||
|
||||
(apntype == "default" && this.usingDefaultAPN("supl"))) {
|
||||
this.deactivateDataCallBySharedApn(apntype);
|
||||
return;
|
||||
}
|
||||
switch (apntype) {
|
||||
case "default":
|
||||
this.dataNetworkInterface.disconnect(apntype);
|
||||
break;
|
||||
case "mms":
|
||||
this.mmsNetworkInterface.disconnect(apntype);
|
||||
break;
|
||||
case "supl":
|
||||
this.suplNetworkInterface.disconnect(apntype);
|
||||
break;
|
||||
default:
|
||||
if (DEBUG) this.debug("Unsupported APN type " + apntype);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
getDataCallStateByType: function getDataCallStateByType(apntype) {
|
||||
// If it's a shared apn type then we can only reuse the
|
||||
// dataNetworkInterface in current design.
|
||||
if (this.usingDefaultAPN(apntype) ||
|
||||
(apntype == "default" && this.usingDefaultAPN("mms")) ||
|
||||
(apntype == "default" && this.usingDefaultAPN("supl"))) {
|
||||
if (this.dataNetworkInterface.inConnectedTypes(apntype)) {
|
||||
return this.dataNetworkInterface.state;
|
||||
}
|
||||
return RIL.GECKO_NETWORK_STATE_UNKNOWN;
|
||||
let apnSetting = this.apnSettings.byType[apntype];
|
||||
if (!apnSetting) {
|
||||
return RIL.GECKO_NETWORK_STATE_UNKNOWN;
|
||||
}
|
||||
switch (apntype) {
|
||||
case "default":
|
||||
return this.dataNetworkInterface.state;
|
||||
case "mms":
|
||||
return this.mmsNetworkInterface.state;
|
||||
case "supl":
|
||||
return this.suplNetworkInterface.state;
|
||||
default:
|
||||
return RIL.GECKO_NETWORK_STATE_UNKNOWN;
|
||||
if (!apnSetting.iface.inConnectedTypes(apntype)) {
|
||||
return RIL.GECKO_NETWORK_STATE_DISCONNECTED;
|
||||
}
|
||||
return apnSetting.iface.state;
|
||||
},
|
||||
|
||||
setupDataCall: function setupDataCall(radioTech, apn, user, passwd, chappap, pdptype) {
|
||||
@ -3361,9 +3352,9 @@ RadioInterface.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
function RILNetworkInterface(radioInterface, type) {
|
||||
function RILNetworkInterface(radioInterface, apnSetting) {
|
||||
this.radioInterface = radioInterface;
|
||||
this.initType = type;
|
||||
this.apnSetting = apnSetting;
|
||||
}
|
||||
|
||||
RILNetworkInterface.prototype = {
|
||||
@ -3432,9 +3423,13 @@ RILNetworkInterface.prototype = {
|
||||
|
||||
dns2: null,
|
||||
|
||||
httpProxyHost: null,
|
||||
get httpProxyHost() {
|
||||
return this.apnSetting.proxy || '';
|
||||
},
|
||||
|
||||
httpProxyPort: null,
|
||||
get httpProxyPort() {
|
||||
return this.apnSetting.port || '';
|
||||
},
|
||||
|
||||
debug: function debug(s) {
|
||||
dump("-*- RILNetworkInterface[" + this.radioInterface.clientId + ":" +
|
||||
@ -3444,7 +3439,7 @@ RILNetworkInterface.prototype = {
|
||||
// nsIRILDataCallback
|
||||
|
||||
dataCallError: function dataCallError(message) {
|
||||
if (message.apn != this.dataCallSettings.apn) {
|
||||
if (message.apn != this.apnSetting.apn) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) this.debug("Data call error on APN: " + message.apn);
|
||||
@ -3460,7 +3455,7 @@ RILNetworkInterface.prototype = {
|
||||
// If data call for this connection does not exist, it could be state
|
||||
// change for new data call. We only update data call state change
|
||||
// if APN name matched.
|
||||
if (!this.cid && datacall.apn != this.dataCallSettings.apn) {
|
||||
if (!this.cid && datacall.apn != this.apnSetting.apn) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
@ -3501,12 +3496,14 @@ RILNetworkInterface.prototype = {
|
||||
// In case the data setting changed while the datacall was being started or
|
||||
// ended, let's re-check the setting and potentially adjust the datacall
|
||||
// state again.
|
||||
if (this == this.radioInterface.dataNetworkInterface) {
|
||||
if (this.radioInterface.apnSettings.byType.default &&
|
||||
(this.radioInterface.apnSettings.byType.default.apn ==
|
||||
this.apnSetting.apn)) {
|
||||
this.radioInterface.updateRILNetworkInterface();
|
||||
}
|
||||
|
||||
if (this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
|
||||
this.registeredAsNetworkInterface) {
|
||||
this.registeredAsNetworkInterface) {
|
||||
gNetworkManager.unregisterNetworkInterface(this);
|
||||
this.registeredAsNetworkInterface = false;
|
||||
this.cid = null;
|
||||
@ -3528,7 +3525,7 @@ RILNetworkInterface.prototype = {
|
||||
registeredAsDataCallCallback: false,
|
||||
registeredAsNetworkInterface: false,
|
||||
connecting: false,
|
||||
dataCallSettings: {},
|
||||
apnSetting: {},
|
||||
|
||||
// APN failed connections. Retry counter
|
||||
apnRetryCounter: 0,
|
||||
@ -3543,7 +3540,7 @@ RILNetworkInterface.prototype = {
|
||||
return this.state == RIL.GECKO_NETWORK_STATE_CONNECTED;
|
||||
},
|
||||
|
||||
connect: function connect(options, apntype) {
|
||||
connect: function connect(apntype) {
|
||||
if (apntype && !this.inConnectedTypes(apntype)) {
|
||||
this.connectedTypes.push(apntype);
|
||||
}
|
||||
@ -3563,40 +3560,32 @@ RILNetworkInterface.prototype = {
|
||||
this.registeredAsDataCallCallback = true;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
// Save the APN data locally for using them in connection retries.
|
||||
this.dataCallSettings = options;
|
||||
}
|
||||
|
||||
if (!this.dataCallSettings.apn) {
|
||||
if (!this.apnSetting.apn) {
|
||||
if (DEBUG) this.debug("APN name is empty, nothing to do.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.httpProxyHost = this.dataCallSettings.httpProxyHost;
|
||||
this.httpProxyPort = this.dataCallSettings.httpProxyPort;
|
||||
|
||||
if (DEBUG) {
|
||||
this.debug("Going to set up data connection with APN " +
|
||||
this.dataCallSettings.apn);
|
||||
this.apnSetting.apn);
|
||||
}
|
||||
let radioTechType = this.radioInterface.rilContext.data.type;
|
||||
let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType);
|
||||
let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.dataCallSettings["authtype"]);
|
||||
let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.apnSetting.authtype);
|
||||
// Use the default authType if the value in database is invalid.
|
||||
// For the case that user might not select the authentication type.
|
||||
if (authType == -1) {
|
||||
if (DEBUG) {
|
||||
this.debug("Invalid authType " + this.dataCallSettings.authtype);
|
||||
this.debug("Invalid authType " + this.apnSetting.authtype);
|
||||
}
|
||||
authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT);
|
||||
}
|
||||
this.radioInterface.setupDataCall(radioTechnology,
|
||||
this.dataCallSettings.apn,
|
||||
this.dataCallSettings.user,
|
||||
this.dataCallSettings.passwd,
|
||||
authType,
|
||||
"IP");
|
||||
this.apnSetting.apn,
|
||||
this.apnSetting.user,
|
||||
this.apnSetting.password,
|
||||
authType,
|
||||
"IP");
|
||||
this.connecting = true;
|
||||
},
|
||||
|
||||
@ -3641,7 +3630,8 @@ RILNetworkInterface.prototype = {
|
||||
}
|
||||
|
||||
if (this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTING ||
|
||||
this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED) {
|
||||
this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED ||
|
||||
this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
let reason = RIL.DATACALL_DEACTIVATE_NO_REASON;
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMMozIccInfo;
|
||||
interface nsIDOMMozMobileConnectionInfo;
|
||||
interface nsIDOMMozMobileICCInfo;
|
||||
interface nsIMobileMessageCallback;
|
||||
interface nsIDOMMozSmsSegmentInfo;
|
||||
interface nsIMobileMessageCallback;
|
||||
|
||||
[scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)]
|
||||
interface nsIRILDataCallInfo : nsISupports
|
||||
@ -59,7 +59,7 @@ interface nsIVoicemailInfo : nsISupports
|
||||
readonly attribute DOMString displayName;
|
||||
};
|
||||
|
||||
[scriptable, uuid(2f1c8055-322e-490a-b1e1-4ccd5d546b3c)]
|
||||
[scriptable, uuid(95e1be50-c912-11e2-8b8b-0800200c9a66)]
|
||||
interface nsIRilContext : nsISupports
|
||||
{
|
||||
readonly attribute DOMString radioState;
|
||||
@ -72,7 +72,7 @@ interface nsIRilContext : nsISupports
|
||||
|
||||
readonly attribute DOMString networkSelectionMode;
|
||||
|
||||
readonly attribute nsIDOMMozMobileICCInfo iccInfo;
|
||||
readonly attribute nsIDOMMozIccInfo iccInfo;
|
||||
|
||||
readonly attribute nsIDOMMozMobileConnectionInfo voice;
|
||||
|
||||
|
@ -837,7 +837,7 @@ GrallocDeprecatedTextureHostOGL::SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceA
|
||||
LayerRenderState
|
||||
GrallocDeprecatedTextureHostOGL::GetRenderState()
|
||||
{
|
||||
if (mBuffer && IsSurfaceDescriptorValid(*mBuffer)) {
|
||||
if (mGraphicBuffer.get()) {
|
||||
|
||||
uint32_t flags = mFlags & NeedsYFlip ? LAYER_RENDER_STATE_Y_FLIPPED : 0;
|
||||
|
||||
@ -854,8 +854,10 @@ GrallocDeprecatedTextureHostOGL::GetRenderState()
|
||||
flags |= LAYER_RENDER_STATE_FORMAT_RB_SWAP;
|
||||
}
|
||||
|
||||
nsIntSize bufferSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight());
|
||||
|
||||
return LayerRenderState(mGraphicBuffer.get(),
|
||||
mBuffer->get_SurfaceDescriptorGralloc().size(),
|
||||
bufferSize,
|
||||
flags);
|
||||
}
|
||||
|
||||
|
@ -734,7 +734,6 @@ AdjustSystemClock(int64_t aDeltaMilliseconds)
|
||||
|
||||
if (ioctl(fd, ANDROID_ALARM_SET_RTC, &now) < 0) {
|
||||
HAL_LOG(("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
hal::NotifySystemClockChange(aDeltaMilliseconds);
|
||||
|
@ -2849,7 +2849,7 @@ function fetch(aURL, aOptions={ loadFromCache: true }) {
|
||||
try {
|
||||
NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) {
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
deferred.reject("Request failed: " + url);
|
||||
deferred.reject(new Error("Request failed: " + url));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2858,7 +2858,7 @@ function fetch(aURL, aOptions={ loadFromCache: true }) {
|
||||
aStream.close();
|
||||
});
|
||||
} catch (ex) {
|
||||
deferred.reject("Request failed: " + url);
|
||||
deferred.reject(new Error("Request failed: " + url));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -2876,7 +2876,7 @@ function fetch(aURL, aOptions={ loadFromCache: true }) {
|
||||
let streamListener = {
|
||||
onStartRequest: function(aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
deferred.reject("Request failed: " + url);
|
||||
deferred.reject(new Error("Request failed: " + url));
|
||||
}
|
||||
},
|
||||
onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) {
|
||||
@ -2884,7 +2884,7 @@ function fetch(aURL, aOptions={ loadFromCache: true }) {
|
||||
},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
deferred.reject("Request failed: " + url);
|
||||
deferred.reject(new Error("Request failed: " + url));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2934,6 +2934,7 @@ function convertToUnicode(aString, aCharset=null) {
|
||||
* An optional prefix for the reported error message.
|
||||
*/
|
||||
function reportError(aError, aPrefix="") {
|
||||
dbg_assert(aError instanceof Error, "Must pass Error objects to reportError");
|
||||
let msg = aPrefix + aError.message + ":\n" + aError.stack;
|
||||
Cu.reportError(msg);
|
||||
dumpn(msg);
|
||||
|
@ -24,8 +24,7 @@ let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|
||||
Cu.import("resource://gre/modules/jsdebugger.jsm");
|
||||
addDebuggerToGlobal(this);
|
||||
|
||||
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
|
||||
const { defer, resolve, reject, all } = promise;
|
||||
loadSubScript.call(this, "resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/SourceMap.jsm");
|
||||
|
||||
@ -198,11 +197,11 @@ var DebuggerServer = {
|
||||
get initialized() this._initialized,
|
||||
|
||||
/**
|
||||
* Performs cleanup tasks before shutting down the debugger server, if no
|
||||
* connections are currently open. Such tasks include clearing any actor
|
||||
* constructors added at runtime. This method should be called whenever a
|
||||
* debugger server is no longer useful, to avoid memory leaks. After this
|
||||
* method returns, the debugger server must be initialized again before use.
|
||||
* Performs cleanup tasks before shutting down the debugger server. Such tasks
|
||||
* include clearing any actor constructors added at runtime. This method
|
||||
* should be called whenever a debugger server is no longer useful, to avoid
|
||||
* memory leaks. After this method returns, the debugger server must be
|
||||
* initialized again before use.
|
||||
*/
|
||||
destroy: function DS_destroy() {
|
||||
if (!this._initialized) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user