Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2013-07-15 17:07:04 -04:00
commit e537debdc8
24 changed files with 628 additions and 363 deletions

View File

@ -1,4 +1,4 @@
{
"revision": "d717e2e751a6bb1303499bde6be9dbd88b275e30",
"revision": "846f8e7089361d42e1362ab591561f94d3bd31e9",
"repo_path": "/integration/gaia-central"
}

View File

@ -228,6 +228,12 @@ let StyleSheet = function(form, debuggee) {
this._client.addListener("propertyChange", this._onPropertyChange);
this._client.addListener("styleApplied", this._onStyleApplied);
// Backwards compatibility
this._client.addListener("sourceLoad-" + this._actor, this._onSourceLoad);
this._client.addListener("propertyChange-" + this._actor, this._onPropertyChange);
this._client.addListener("styleApplied-" + this._actor, this._onStyleApplied);
// set initial property values
for (let attr in form) {
this[attr] = form[attr];
@ -324,5 +330,9 @@ StyleSheet.prototype = {
this._client.removeListener("sourceLoad", this._onSourceLoad);
this._client.removeListener("propertyChange", this._onPropertyChange);
this._client.removeListener("styleApplied", this._onStyleApplied);
this._client.removeListener("sourceLoad-" + this._actor, this._onSourceLoad);
this._client.removeListener("propertyChange-" + this._actor, this._onPropertyChange);
this._client.removeListener("styleApplied-" + this._actor, this._onStyleApplied);
}
}

View File

@ -1270,6 +1270,7 @@ BluetoothHfpManager::GetNumberOfCalls(uint16_t aState)
void
BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
uint16_t aCallState,
const nsAString& aError,
const nsAString& aNumber,
const bool aIsOutgoing,
bool aSend)
@ -1391,7 +1392,6 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
case nsITelephonyProvider::CALL_STATE_DISCONNECTED:
switch (prevCallState) {
case nsITelephonyProvider::CALL_STATE_INCOMING:
case nsITelephonyProvider::CALL_STATE_BUSY:
// Incoming call, no break
sStopSendingRingFlag = true;
case nsITelephonyProvider::CALL_STATE_DIALING:
@ -1424,7 +1424,7 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_DISCONNECTED)) {
// In order to let user hear busy tone via connected Bluetooth headset,
// we postpone the timing of dropping SCO.
if (prevCallState != nsITelephonyProvider::CALL_STATE_BUSY) {
if (!(aError.Equals(NS_LITERAL_STRING("BusyError")))) {
DisconnectSco();
} else {
// Close Sco later since Dialer is still playing busy tone via HF.

View File

@ -86,8 +86,8 @@ public:
* @param aSend A boolean indicates whether we need to notify headset or not
*/
void HandleCallStateChanged(uint32_t aCallIndex, uint16_t aCallState,
const nsAString& aNumber, const bool aIsOutgoing,
bool aSend);
const nsAString& aError, const nsAString& aNumber,
const bool aIsOutgoing, bool aSend);
bool IsConnected();
bool IsScoConnected();

View File

@ -35,7 +35,7 @@ TelephonyListener::CallStateChanged(uint32_t aCallIndex,
bool aIsEmergency)
{
BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
hfp->HandleCallStateChanged(aCallIndex, aCallState, aNumber,
hfp->HandleCallStateChanged(aCallIndex, aCallState, EmptyString(), aNumber,
aIsOutgoing, true);
return NS_OK;
@ -57,7 +57,7 @@ TelephonyListener::EnumerateCallState(uint32_t aCallIndex,
bool* aResult)
{
BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
hfp->HandleCallStateChanged(aCallIndex, aCallState, aNumber,
hfp->HandleCallStateChanged(aCallIndex, aCallState, EmptyString(), aNumber,
aIsOutgoing, false);
*aResult = true;
return NS_OK;
@ -77,7 +77,7 @@ TelephonyListener::NotifyError(int32_t aCallIndex,
// via setting CALL_STATE_DISCONNECTED
hfp->HandleCallStateChanged(aCallIndex,
nsITelephonyProvider::CALL_STATE_DISCONNECTED,
EmptyString(), false, true);
aError, EmptyString(), false, true);
NS_WARNING("Reset the call state due to call transition ends abnormally");
}

View File

@ -640,6 +640,8 @@ ContactManager.prototype = {
case "Contact:Save:Return:KO":
case "Contact:Remove:Return:KO":
case "Contacts:Clear:Return:KO":
case "Contacts:GetRevision:Return:KO":
case "Contacts:Count:Return:KO":
req = this.getRequest(msg.requestID);
if (req)
Services.DOMRequest.fireError(req.request, msg.errorMsg);

View File

@ -93,284 +93,8 @@ ContactDB.prototype = {
_dispatcher: {},
upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
if (DEBUG) debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
let db = aDb;
let objectStore;
for (let currVersion = aOldVersion; currVersion < aNewVersion; currVersion++) {
if (currVersion == 0) {
/**
* Create the initial database schema.
*
* The schema of records stored is as follows:
*
* {id: "...", // UUID
* published: Date(...), // First published date.
* updated: Date(...), // Last updated date.
* properties: {...} // Object holding the ContactProperties
* }
*/
if (DEBUG) debug("create schema");
objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"});
// Properties indexes
objectStore.createIndex("familyName", "properties.familyName", { multiEntry: true });
objectStore.createIndex("givenName", "properties.givenName", { multiEntry: true });
objectStore.createIndex("familyNameLowerCase", "search.familyName", { multiEntry: true });
objectStore.createIndex("givenNameLowerCase", "search.givenName", { multiEntry: true });
objectStore.createIndex("telLowerCase", "search.tel", { multiEntry: true });
objectStore.createIndex("emailLowerCase", "search.email", { multiEntry: true });
} else if (currVersion == 1) {
if (DEBUG) debug("upgrade 1");
// Create a new scheme for the tel field. We move from an array of tel-numbers to an array of
// ContactTelephone.
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Delete old tel index.
if (objectStore.indexNames.contains("tel")) {
objectStore.deleteIndex("tel");
}
// Upgrade existing tel field in the DB.
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (DEBUG) debug("upgrade tel1: " + JSON.stringify(cursor.value));
for (let number in cursor.value.properties.tel) {
cursor.value.properties.tel[number] = {number: number};
}
cursor.update(cursor.value);
if (DEBUG) debug("upgrade tel2: " + JSON.stringify(cursor.value));
cursor.continue();
}
};
// Create new searchable indexes.
objectStore.createIndex("tel", "search.tel", { multiEntry: true });
objectStore.createIndex("category", "properties.category", { multiEntry: true });
} else if (currVersion == 2) {
if (DEBUG) debug("upgrade 2");
// Create a new scheme for the email field. We move from an array of emailaddresses to an array of
// ContactEmail.
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Delete old email index.
if (objectStore.indexNames.contains("email")) {
objectStore.deleteIndex("email");
}
// Upgrade existing email field in the DB.
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.email) {
if (DEBUG) debug("upgrade email1: " + JSON.stringify(cursor.value));
cursor.value.properties.email =
cursor.value.properties.email.map(function(address) { return { address: address }; });
cursor.update(cursor.value);
if (DEBUG) debug("upgrade email2: " + JSON.stringify(cursor.value));
}
cursor.continue();
}
};
// Create new searchable indexes.
objectStore.createIndex("email", "search.email", { multiEntry: true });
} else if (currVersion == 3) {
if (DEBUG) debug("upgrade 3");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Upgrade existing impp field in the DB.
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.impp) {
if (DEBUG) debug("upgrade impp1: " + JSON.stringify(cursor.value));
cursor.value.properties.impp =
cursor.value.properties.impp.map(function(value) { return { value: value }; });
cursor.update(cursor.value);
if (DEBUG) debug("upgrade impp2: " + JSON.stringify(cursor.value));
}
cursor.continue();
}
};
// Upgrade existing url field in the DB.
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.url) {
if (DEBUG) debug("upgrade url1: " + JSON.stringify(cursor.value));
cursor.value.properties.url =
cursor.value.properties.url.map(function(value) { return { value: value }; });
cursor.update(cursor.value);
if (DEBUG) debug("upgrade impp2: " + JSON.stringify(cursor.value));
}
cursor.continue();
}
};
} else if (currVersion == 4) {
if (DEBUG) debug("Add international phone numbers upgrade");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
cursor.value.properties.tel.forEach(
function(duple) {
let parsedNumber = PhoneNumberUtils.parse(duple.value.toString());
if (parsedNumber) {
if (DEBUG) {
debug("InternationalFormat: " + parsedNumber.internationalFormat);
debug("InternationalNumber: " + parsedNumber.internationalNumber);
debug("NationalNumber: " + parsedNumber.nationalNumber);
debug("NationalFormat: " + parsedNumber.nationalFormat);
}
if (duple.value.toString() !== parsedNumber.internationalNumber) {
cursor.value.search.tel.push(parsedNumber.internationalNumber);
}
} else {
dump("Warning: No international number found for " + duple.value + "\n");
}
}
)
cursor.update(cursor.value);
}
if (DEBUG) debug("upgrade2 : " + JSON.stringify(cursor.value));
cursor.continue();
}
};
} else if (currVersion == 5) {
if (DEBUG) debug("Add index for equals tel searches");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Delete old tel index (not on the right field).
if (objectStore.indexNames.contains("tel")) {
objectStore.deleteIndex("tel");
}
// Create new index for "equals" searches
objectStore.createIndex("tel", "search.exactTel", { multiEntry: true });
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
cursor.value.properties.tel.forEach(
function(duple) {
let number = duple.value.toString();
let parsedNumber = PhoneNumberUtils.parse(number);
cursor.value.search.exactTel = [number];
if (parsedNumber &&
parsedNumber.internationalNumber &&
number !== parsedNumber.internationalNumber) {
cursor.value.search.exactTel.push(parsedNumber.internationalNumber);
}
}
)
cursor.update(cursor.value);
}
if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
cursor.continue();
}
};
} else if (currVersion == 6) {
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
let names = objectStore.indexNames;
let blackList = ["tel", "familyName", "givenName", "familyNameLowerCase",
"givenNameLowerCase", "telLowerCase", "category", "email",
"emailLowerCase"];
for (var i = 0; i < names.length; i++) {
if (blackList.indexOf(names[i]) < 0) {
objectStore.deleteIndex(names[i]);
}
}
} else if (currVersion == 7) {
if (DEBUG) debug("Adding object store for cached searches");
db.createObjectStore(SAVED_GETALL_STORE_NAME);
} else if (currVersion == 8) {
if (DEBUG) debug("Make exactTel only contain the value entered by the user");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
cursor.value.search.exactTel = [];
cursor.value.properties.tel.forEach(
function(tel) {
let normalized = PhoneNumberUtils.normalize(tel.value.toString());
cursor.value.search.exactTel.push(normalized);
}
);
cursor.update(cursor.value);
}
cursor.continue();
}
};
} else if (currVersion == 9) {
// no-op, see https://bugzilla.mozilla.org/show_bug.cgi?id=883770#c16
} else if (currVersion == 10) {
if (DEBUG) debug("Adding object store for database revision");
db.createObjectStore(REVISION_STORE).put(0, REVISION_KEY);
} else if (currVersion == 11) {
if (DEBUG) debug("Add a telMatch index with national and international numbers");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
if (!objectStore.indexNames.contains("telMatch")) {
objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
}
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
cursor.value.search.parsedTel = [];
cursor.value.properties.tel.forEach(
function(tel) {
let parsed = PhoneNumberUtils.parse(tel.value.toString());
if (parsed) {
cursor.value.search.parsedTel.push(parsed.nationalNumber);
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.nationalFormat));
cursor.value.search.parsedTel.push(parsed.internationalNumber);
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.internationalFormat));
}
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(tel.value.toString()));
}
);
cursor.update(cursor.value);
}
cursor.continue();
}
};
}
// Increment the DB revision on future schema changes as well
if (currVersion > 11) {
this.incrementRevision(aTransaction);
}
}
// Add default contacts
if (aOldVersion == 0) {
function loadInitialContacts() {
// Add default contacts
let jsm = {};
Cu.import("resource://gre/modules/FileUtils.jsm", jsm);
Cu.import("resource://gre/modules/NetUtil.jsm", jsm);
@ -419,6 +143,334 @@ ContactDB.prototype = {
objectStore.put(contact);
}
}
if (DEBUG) debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
let db = aDb;
let objectStore;
let steps = [
function upgrade0to1() {
/**
* Create the initial database schema.
*
* The schema of records stored is as follows:
*
* {id: "...", // UUID
* published: Date(...), // First published date.
* updated: Date(...), // Last updated date.
* properties: {...} // Object holding the ContactProperties
* }
*/
if (DEBUG) debug("create schema");
objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"});
// Properties indexes
objectStore.createIndex("familyName", "properties.familyName", { multiEntry: true });
objectStore.createIndex("givenName", "properties.givenName", { multiEntry: true });
objectStore.createIndex("familyNameLowerCase", "search.familyName", { multiEntry: true });
objectStore.createIndex("givenNameLowerCase", "search.givenName", { multiEntry: true });
objectStore.createIndex("telLowerCase", "search.tel", { multiEntry: true });
objectStore.createIndex("emailLowerCase", "search.email", { multiEntry: true });
next();
},
function upgrade1to2() {
if (DEBUG) debug("upgrade 1");
// Create a new scheme for the tel field. We move from an array of tel-numbers to an array of
// ContactTelephone.
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Delete old tel index.
if (objectStore.indexNames.contains("tel")) {
objectStore.deleteIndex("tel");
}
// Upgrade existing tel field in the DB.
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (DEBUG) debug("upgrade tel1: " + JSON.stringify(cursor.value));
for (let number in cursor.value.properties.tel) {
cursor.value.properties.tel[number] = {number: number};
}
cursor.update(cursor.value);
if (DEBUG) debug("upgrade tel2: " + JSON.stringify(cursor.value));
cursor.continue();
} else {
next();
}
};
// Create new searchable indexes.
objectStore.createIndex("tel", "search.tel", { multiEntry: true });
objectStore.createIndex("category", "properties.category", { multiEntry: true });
},
function upgrade2to3() {
if (DEBUG) debug("upgrade 2");
// Create a new scheme for the email field. We move from an array of emailaddresses to an array of
// ContactEmail.
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Delete old email index.
if (objectStore.indexNames.contains("email")) {
objectStore.deleteIndex("email");
}
// Upgrade existing email field in the DB.
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.email) {
if (DEBUG) debug("upgrade email1: " + JSON.stringify(cursor.value));
cursor.value.properties.email =
cursor.value.properties.email.map(function(address) { return { address: address }; });
cursor.update(cursor.value);
if (DEBUG) debug("upgrade email2: " + JSON.stringify(cursor.value));
}
cursor.continue();
} else {
next();
}
};
// Create new searchable indexes.
objectStore.createIndex("email", "search.email", { multiEntry: true });
},
function upgrade3to4() {
if (DEBUG) debug("upgrade 3");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Upgrade existing impp field in the DB.
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.impp) {
if (DEBUG) debug("upgrade impp1: " + JSON.stringify(cursor.value));
cursor.value.properties.impp =
cursor.value.properties.impp.map(function(value) { return { value: value }; });
cursor.update(cursor.value);
if (DEBUG) debug("upgrade impp2: " + JSON.stringify(cursor.value));
}
cursor.continue();
}
};
// Upgrade existing url field in the DB.
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.url) {
if (DEBUG) debug("upgrade url1: " + JSON.stringify(cursor.value));
cursor.value.properties.url =
cursor.value.properties.url.map(function(value) { return { value: value }; });
cursor.update(cursor.value);
if (DEBUG) debug("upgrade impp2: " + JSON.stringify(cursor.value));
}
cursor.continue();
} else {
next();
}
};
},
function upgrade4to5() {
if (DEBUG) debug("Add international phone numbers upgrade");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
cursor.value.properties.tel.forEach(
function(duple) {
let parsedNumber = PhoneNumberUtils.parse(duple.value.toString());
if (parsedNumber) {
if (DEBUG) {
debug("InternationalFormat: " + parsedNumber.internationalFormat);
debug("InternationalNumber: " + parsedNumber.internationalNumber);
debug("NationalNumber: " + parsedNumber.nationalNumber);
debug("NationalFormat: " + parsedNumber.nationalFormat);
}
if (duple.value.toString() !== parsedNumber.internationalNumber) {
cursor.value.search.tel.push(parsedNumber.internationalNumber);
}
} else {
dump("Warning: No international number found for " + duple.value + "\n");
}
}
)
cursor.update(cursor.value);
}
if (DEBUG) debug("upgrade2 : " + JSON.stringify(cursor.value));
cursor.continue();
} else {
next();
}
};
},
function upgrade5to6() {
if (DEBUG) debug("Add index for equals tel searches");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Delete old tel index (not on the right field).
if (objectStore.indexNames.contains("tel")) {
objectStore.deleteIndex("tel");
}
// Create new index for "equals" searches
objectStore.createIndex("tel", "search.exactTel", { multiEntry: true });
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
cursor.value.properties.tel.forEach(
function(duple) {
let number = duple.value.toString();
let parsedNumber = PhoneNumberUtils.parse(number);
cursor.value.search.exactTel = [number];
if (parsedNumber &&
parsedNumber.internationalNumber &&
number !== parsedNumber.internationalNumber) {
cursor.value.search.exactTel.push(parsedNumber.internationalNumber);
}
}
)
cursor.update(cursor.value);
}
if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
cursor.continue();
} else {
next();
}
};
},
function upgrade6to7() {
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
let names = objectStore.indexNames;
let blackList = ["tel", "familyName", "givenName", "familyNameLowerCase",
"givenNameLowerCase", "telLowerCase", "category", "email",
"emailLowerCase"];
for (var i = 0; i < names.length; i++) {
if (blackList.indexOf(names[i]) < 0) {
objectStore.deleteIndex(names[i]);
}
}
next();
},
function upgrade7to8() {
if (DEBUG) debug("Adding object store for cached searches");
db.createObjectStore(SAVED_GETALL_STORE_NAME);
next();
},
function upgrade8to9() {
if (DEBUG) debug("Make exactTel only contain the value entered by the user");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
cursor.value.search.exactTel = [];
cursor.value.properties.tel.forEach(
function(tel) {
let normalized = PhoneNumberUtils.normalize(tel.value.toString());
cursor.value.search.exactTel.push(normalized);
}
);
cursor.update(cursor.value);
}
cursor.continue();
} else {
next();
}
};
},
function upgrade9to10() {
// no-op, see https://bugzilla.mozilla.org/show_bug.cgi?id=883770#c16
next();
},
function upgrade10to11() {
if (DEBUG) debug("Adding object store for database revision");
db.createObjectStore(REVISION_STORE).put(0, REVISION_KEY);
next();
},
function upgrade11to12() {
if (DEBUG) debug("Add a telMatch index with national and international numbers");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
if (!objectStore.indexNames.contains("telMatch")) {
objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
}
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.properties.tel) {
cursor.value.search.parsedTel = [];
cursor.value.properties.tel.forEach(
function(tel) {
let parsed = PhoneNumberUtils.parse(tel.value.toString());
if (parsed) {
cursor.value.search.parsedTel.push(parsed.nationalNumber);
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.nationalFormat));
cursor.value.search.parsedTel.push(parsed.internationalNumber);
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.internationalFormat));
}
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(tel.value.toString()));
}
);
cursor.update(cursor.value);
}
cursor.continue();
} else {
next();
}
};
}
];
let index = aOldVersion;
let outer = this;
function next() {
if (index == aNewVersion) {
if (aOldVersion === 0) {
loadInitialContacts();
}
outer.incrementRevision(aTransaction);
return;
}
try {
var i = index++;
if (DEBUG) debug("Upgrade step: " + i + "\n");
steps[i]();
} catch(ex) {
dump("Caught exception" + ex);
aTransaction.abort();
return;
}
};
if (aNewVersion > steps.length) {
dump("Contacts DB upgrade error!");
aTransaction.abort();
}
next();
},
makeImport: function makeImport(aContact) {
@ -739,22 +791,22 @@ ContactDB.prototype = {
}.bind(this), aFailureCb);
},
getRevision: function CDB_getRevision(aSuccessCb) {
getRevision: function CDB_getRevision(aSuccessCb, aErrorCb) {
if (DEBUG) debug("getRevision");
this.newTxn("readonly", REVISION_STORE, function (txn, store) {
store.get(REVISION_KEY).onsuccess = function (e) {
aSuccessCb(e.target.result);
};
});
},null, aErrorCb);
},
getCount: function CDB_getCount(aSuccessCb) {
getCount: function CDB_getCount(aSuccessCb, aErrorCb) {
if (DEBUG) debug("getCount");
this.newTxn("readonly", STORE_NAME, function (txn, store) {
store.count().onsuccess = function (e) {
aSuccessCb(e.target.result);
};
});
}, null, aErrorCb);
},
/*

View File

@ -205,7 +205,8 @@ let ContactService = {
requestID: msg.requestID,
revision: revision
});
}
},
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:GetRevision:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
);
break;
case "Contacts:GetCount":
@ -218,7 +219,8 @@ let ContactService = {
requestID: msg.requestID,
count: count
});
}
},
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Count:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
);
break;
case "Contacts:RegisterForMessages":

View File

@ -257,10 +257,12 @@ ok(mozContacts, "mozContacts exists");
ok("mozContact" in window, "mozContact exists");
var steps = [
function() {
mozContacts.getRevision().onsuccess = function(e) {
req = mozContacts.getRevision();
req.onsuccess = function(e) {
initialRev = e.target.result;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");

View File

@ -730,19 +730,28 @@ ContentParent::TransformPreallocatedIntoApp(const nsAString& aAppManifestURL,
}
void
ContentParent::ShutDownProcess()
ContentParent::ShutDownProcess(bool aFromActorDestroyed)
{
if (!mIsDestroyed) {
mIsDestroyed = true;
const InfallibleTArray<PIndexedDBParent*>& idbParents =
ManagedPIndexedDBParent();
for (uint32_t i = 0; i < idbParents.Length(); ++i) {
static_cast<IndexedDBParent*>(idbParents[i])->Disconnect();
}
// Close() can only be called once. It kicks off the
// destruction sequence.
Close();
mIsDestroyed = true;
if (aFromActorDestroyed) {
// If ActorDestroyed() is calling this method but mIsDestroyed was false,
// we're in an error state.
AsyncChannel* channel = GetIPCChannel();
if (channel) {
channel->CloseWithError();
}
} else {
// Close() can only be called once: It kicks off the destruction sequence.
Close();
}
}
// NB: must MarkAsDead() here so that this isn't accidentally
// returned from Get*() while in the midst of shutdown.
@ -948,6 +957,11 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
}
// If the child process was terminated due to a SIGKIL, ShutDownProcess
// might not have been called yet. We must call it to ensure that our
// channel is closed, etc.
ShutDownProcess(/* aForce = */ true);
MessageLoop::current()->
PostTask(FROM_HERE,
NewRunnableFunction(DelayedDeleteSubprocess, mSubprocess));
@ -1006,7 +1020,8 @@ ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
if (ManagedPBrowserParent().Length() == 1) {
MessageLoop::current()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &ContentParent::ShutDownProcess));
NewRunnableMethod(this, &ContentParent::ShutDownProcess,
/* force */ false));
}
}
@ -1464,7 +1479,7 @@ ContentParent::Observe(nsISupports* aSubject,
const PRUnichar* aData)
{
if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) {
ShutDownProcess();
ShutDownProcess(/* force */ false);
NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess");
}

View File

@ -243,8 +243,14 @@ private:
* will return false and this ContentParent will not be returned
* by the Get*() funtions. However, the shutdown sequence itself
* may be asynchronous.
*
* If aFromActorDestroyed is true and this is the first call to
* ShutDownProcess, then we'll close our channel using CloseWithError()
* rather than vanilla Close(). CloseWithError() indicates to IPC that this
* is an abnormal shutdown (e.g. a crash); when the process shuts down
* cleanly, ShutDownProcess runs before ActorDestroyed.
*/
void ShutDownProcess();
void ShutDownProcess(bool aFromActorDestroyed);
PCompositorParent*
AllocPCompositorParent(mozilla::ipc::Transport* aTransport,

View File

@ -34,15 +34,6 @@ this.SystemMessagePermissionsTable = {
"bluetooth-dialer-command": {
"telephony": []
},
"bluetooth-requestconfirmation": {
"bluetooth": []
},
"bluetooth-requestpasskey": {
"bluetooth": []
},
"bluetooth-requestpincode": {
"bluetooth": []
},
"bluetooth-authorize": {
"bluetooth": []
},
@ -52,6 +43,9 @@ this.SystemMessagePermissionsTable = {
"bluetooth-pairedstatuschanged": {
"bluetooth": []
},
"bluetooth-a2dp-status-changed": {
"bluetooth": []
},
"bluetooth-hfp-status-changed": {
"bluetooth": []
},

View File

@ -780,6 +780,11 @@ MobileMessageDatabaseService.prototype = {
if (DEBUG) {
debug("MMS: part[" + i + "]: " + JSON.stringify(part));
}
// Sometimes the part is incomplete because the device reboots when
// downloading MMS. Don't need to expose this part to the content.
if (!part) {
continue;
}
let partHeaders = part["headers"];
let partContent = part["content"];

View File

@ -194,8 +194,6 @@ function convertRILCallState(state) {
case RIL.CALL_STATE_INCOMING:
case RIL.CALL_STATE_WAITING:
return nsITelephonyProvider.CALL_STATE_INCOMING;
case RIL.CALL_STATE_BUSY:
return nsITelephonyProvider.CALL_STATE_BUSY;
default:
throw new Error("Unknown rilCallState: " + state);
}

View File

@ -442,7 +442,6 @@ this.CALL_STATE_DIALING = 2;
this.CALL_STATE_ALERTING = 3;
this.CALL_STATE_INCOMING = 4;
this.CALL_STATE_WAITING = 5;
this.CALL_STATE_BUSY = 6;
this.TOA_INTERNATIONAL = 0x91;
this.TOA_UNKNOWN = 0x81;

View File

@ -4690,11 +4690,6 @@ RIL[REQUEST_LAST_CALL_FAIL_CAUSE] = function REQUEST_LAST_CALL_FAIL_CAUSE(length
case CALL_FAIL_NORMAL:
this._handleDisconnectedCall(options);
break;
case CALL_FAIL_BUSY:
options.state = CALL_STATE_BUSY;
this._handleChangedCallState(options);
this._handleDisconnectedCall(options);
break;
default:
options.rilMessageType = "callError";
options.errorMsg = RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[failCause];

View File

@ -61,9 +61,6 @@ TelephonyCall::ChangeStateInternal(uint16_t aCallState, bool aFireEvents)
case nsITelephonyProvider::CALL_STATE_ALERTING:
stateString.AssignLiteral("alerting");
break;
case nsITelephonyProvider::CALL_STATE_BUSY:
stateString.AssignLiteral("busy");
break;
case nsITelephonyProvider::CALL_STATE_CONNECTING:
stateString.AssignLiteral("connecting");
break;
@ -269,7 +266,6 @@ TelephonyCall::Resume()
NS_IMPL_EVENT_HANDLER(TelephonyCall, statechange)
NS_IMPL_EVENT_HANDLER(TelephonyCall, dialing)
NS_IMPL_EVENT_HANDLER(TelephonyCall, alerting)
NS_IMPL_EVENT_HANDLER(TelephonyCall, busy)
NS_IMPL_EVENT_HANDLER(TelephonyCall, connecting)
NS_IMPL_EVENT_HANDLER(TelephonyCall, connected)
NS_IMPL_EVENT_HANDLER(TelephonyCall, disconnecting)

View File

@ -8,7 +8,7 @@
interface nsIDOMEventListener;
[scriptable, builtinclass, uuid(22e44e8c-cb74-44f2-abe6-b37e9f42ea79)]
[scriptable, builtinclass, uuid(74d240f5-a379-4ac0-a085-a7f714189a27)]
interface nsIDOMTelephonyCall : nsIDOMEventTarget
{
readonly attribute DOMString number;
@ -32,7 +32,6 @@ interface nsIDOMTelephonyCall : nsIDOMEventTarget
[implicit_jscontext] attribute jsval ondialing;
[implicit_jscontext] attribute jsval onalerting;
[implicit_jscontext] attribute jsval onbusy;
[implicit_jscontext] attribute jsval onconnecting;
[implicit_jscontext] attribute jsval onconnected;
[implicit_jscontext] attribute jsval ondisconnecting;

View File

@ -83,15 +83,14 @@ interface nsITelephonyProvider : nsISupports
const unsigned short CALL_STATE_UNKNOWN = 0;
const unsigned short CALL_STATE_DIALING = 1;
const unsigned short CALL_STATE_ALERTING = 2;
const unsigned short CALL_STATE_BUSY = 3;
const unsigned short CALL_STATE_CONNECTING = 4;
const unsigned short CALL_STATE_CONNECTED = 5;
const unsigned short CALL_STATE_HOLDING = 6;
const unsigned short CALL_STATE_HELD = 7;
const unsigned short CALL_STATE_RESUMING = 8;
const unsigned short CALL_STATE_DISCONNECTING = 9;
const unsigned short CALL_STATE_DISCONNECTED = 10;
const unsigned short CALL_STATE_INCOMING = 11;
const unsigned short CALL_STATE_CONNECTING = 3;
const unsigned short CALL_STATE_CONNECTED = 4;
const unsigned short CALL_STATE_HOLDING = 5;
const unsigned short CALL_STATE_HELD = 6;
const unsigned short CALL_STATE_RESUMING = 7;
const unsigned short CALL_STATE_DISCONNECTING = 8;
const unsigned short CALL_STATE_DISCONNECTED = 9;
const unsigned short CALL_STATE_INCOMING = 10;
/**
* Called when a content process registers receiving unsolicited messages from

View File

@ -92,10 +92,10 @@ function dial() {
function busy() {
log("The receiver is busy.");
outgoing.onbusy = function onbusy(event) {
log("Received 'busy' call event.");
outgoing.onerror = function onerror(event) {
log("Received 'error' call event.");
is(outgoing, event.call);
is(outgoing.state, "busy");
is(event.call.error.name, "BusyError");
runEmulatorCmd("gsm list", function(result) {
log("Call list is now: " + result);
@ -103,6 +103,7 @@ function busy() {
cleanUp();
});
};
runEmulatorCmd("gsm busy " + number);
};

View File

@ -101,11 +101,11 @@ namespace mozilla {
* One hint: if you're writing a move constructor where the type has members
* that should be moved themselves, it's much nicer to write this:
*
* C(MoveRef<C> c) : x(c->x), y(c->y) { }
* C(MoveRef<C> c) : x(Move(c->x)), y(Move(c->y)) { }
*
* than the equivalent:
*
* C(MoveRef<C> c) { new(&x) X(c->x); new(&y) Y(c->y); }
* C(MoveRef<C> c) { new(&x) X(Move(c->x)); new(&y) Y(Move(c->y)); }
*
* especially since GNU C++ fails to notice that this does indeed initialize x
* and y, which may matter if they're const.

View File

@ -187,7 +187,7 @@ class BaseBootstrapper(object):
info = self.check_output([hg, '--version']).splitlines()[0]
match = re.search('version ([^\)]+)', info)
match = re.search('version ([^\+\)]+)', info)
if not match:
print('ERROR: Unable to identify Mercurial version.')
return True, False, None

View File

@ -36,6 +36,16 @@ this.Log4Moz = {
20: "DEBUG",
10: "TRACE",
0: "ALL"
},
Numbers: {
"FATAL": 70,
"ERROR": 60,
"WARN": 50,
"INFO": 40,
"CONFIG": 30,
"DEBUG": 20,
"TRACE": 10,
"ALL": 0,
}
},
@ -55,6 +65,7 @@ this.Log4Moz = {
Formatter: Formatter,
BasicFormatter: BasicFormatter,
StructuredFormatter: StructuredFormatter,
Appender: Appender,
DumpAppender: DumpAppender,
@ -109,10 +120,15 @@ this.Log4Moz = {
* LogMessage
* Encapsulates a single log event's data
*/
function LogMessage(loggerName, level, message){
function LogMessage(loggerName, level, message, params) {
this.loggerName = loggerName;
this.level = level;
this.message = message;
this.params = params;
// The _structured field will correspond to whether this message is to
// be interpreted as a structured message.
this._structured = this.params && this.params.action;
this.time = Date.now();
}
LogMessage.prototype = {
@ -123,8 +139,12 @@ LogMessage.prototype = {
},
toString: function LogMsg_toString(){
return "LogMessage [" + this.time + " " + this.level + " " +
this.message + "]";
let msg = "LogMessage [" + this.time + " " + this.level + " " +
this.message;
if (this.params) {
msg += " " + JSON.stringify(this.params);
}
return msg + "]"
}
};
@ -211,7 +231,39 @@ Logger.prototype = {
this.updateAppenders();
},
log: function Logger_log(level, string) {
/**
* Logs a structured message object.
*
* @param action
* (string) A message action, one of a set of actions known to the
* log consumer.
* @param params
* (object) Parameters to be included in the message.
* If _level is included as a key and the corresponding value
* is a number or known level name, the message will be logged
* at the indicated level.
*/
logStructured: function (action, params) {
if (!action) {
throw "An action is required when logging a structured message.";
}
if (!params) {
return this.log(this.level, undefined, {"action": action});
}
if (typeof params != "object") {
throw "The params argument is required to be an object.";
}
let level = params._level || this.level;
if ((typeof level == "string") && level in Log4Moz.Level.Numbers) {
level = Log4Moz.Level.Numbers[level];
}
params.action = action;
this.log(level, params._message, params);
},
log: function (level, string, params) {
if (this.level > level)
return;
@ -224,32 +276,32 @@ Logger.prototype = {
continue;
}
if (!message) {
message = new LogMessage(this._name, level, string);
message = new LogMessage(this._name, level, string, params);
}
appender.append(message);
}
},
fatal: function Logger_fatal(string) {
this.log(Log4Moz.Level.Fatal, string);
fatal: function (string, params) {
this.log(Log4Moz.Level.Fatal, string, params);
},
error: function Logger_error(string) {
this.log(Log4Moz.Level.Error, string);
error: function (string, params) {
this.log(Log4Moz.Level.Error, string, params);
},
warn: function Logger_warn(string) {
this.log(Log4Moz.Level.Warn, string);
warn: function (string, params) {
this.log(Log4Moz.Level.Warn, string, params);
},
info: function Logger_info(string) {
this.log(Log4Moz.Level.Info, string);
info: function (string, params) {
this.log(Log4Moz.Level.Info, string, params);
},
config: function Logger_config(string) {
this.log(Log4Moz.Level.Config, string);
config: function (string, params) {
this.log(Log4Moz.Level.Config, string, params);
},
debug: function Logger_debug(string) {
this.log(Log4Moz.Level.Debug, string);
debug: function (string, params) {
this.log(Log4Moz.Level.Debug, string, params);
},
trace: function Logger_trace(string) {
this.log(Log4Moz.Level.Trace, string);
trace: function (string, params) {
this.log(Log4Moz.Level.Trace, string, params);
}
};
@ -314,8 +366,8 @@ LoggerRepository.prototype = {
/*
* Formatters
* These massage a LogMessage into whatever output is desired
* Only the BasicFormatter is currently implemented
* These massage a LogMessage into whatever output is desired.
* BasicFormatter and StructuredFormatter are implemented here.
*/
// Abstract formatter
@ -324,7 +376,7 @@ Formatter.prototype = {
format: function Formatter_format(message) {}
};
// Basic formatter that doesn't do anything fancy
// Basic formatter that doesn't do anything fancy.
function BasicFormatter(dateFormat) {
if (dateFormat)
this.dateFormat = dateFormat;
@ -340,6 +392,36 @@ BasicFormatter.prototype = {
}
};
// Structured formatter that outputs JSON based on message data.
// This formatter will format unstructured messages by supplying
// default values.
function StructuredFormatter() { }
StructuredFormatter.prototype = {
__proto__: Formatter.prototype,
format: function (logMessage) {
let output = {
_time: logMessage.time,
_namespace: logMessage.loggerName,
_level: logMessage.levelDesc
};
for (let key in logMessage.params) {
output[key] = logMessage.params[key];
}
if (!output.action) {
output.action = "UNKNOWN";
}
if (!output._message && logMessage.message) {
output._message = logMessage.message;
}
return JSON.stringify(output);
}
}
/*
* Appenders
* These can be attached to Loggers to log to different places

View File

@ -41,8 +41,9 @@ add_test(function test_Logger() {
log.debug("this should be logged but not appended.");
do_check_eq(appender.messages.length, 1);
do_check_true(appender.messages[0].indexOf("info test") > 0);
do_check_true(appender.messages[0].indexOf("INFO") > 0);
let msgRe = /\d+\ttest.logger\t\INFO\tinfo test/;
do_check_true(msgRe.test(appender.messages[0]));
run_next_test();
});
@ -69,6 +70,113 @@ add_test(function test_Logger_parent() {
run_next_test();
});
// A utility method for checking object equivalence.
// Fields with a reqular expression value in expected will be tested
// against the corresponding value in actual. Otherwise objects
// are expected to have the same keys and equal values.
function checkObjects(expected, actual) {
do_check_true(expected instanceof Object);
do_check_true(actual instanceof Object);
for (let key in expected) {
do_check_neq(actual[key], undefined);
if (expected[key] instanceof RegExp) {
do_check_true(expected[key].test(actual[key].toString()));
} else {
if (expected[key] instanceof Object) {
checkObjects(expected[key], actual[key]);
} else {
do_check_eq(expected[key], actual[key]);
}
}
}
for (let key in actual) {
do_check_neq(expected[key], undefined);
}
}
add_test(function test_StructuredLogCommands() {
let appender = new MockAppender(new Log4Moz.StructuredFormatter());
let logger = Log4Moz.repository.getLogger("test.StructuredOutput");
logger.addAppender(appender);
logger.level = Log4Moz.Level.Info;
logger.logStructured("test_message", {_message: "message string one"});
logger.logStructured("test_message", {_message: "message string two",
_level: "ERROR",
source_file: "test_log4moz.js"});
logger.logStructured("test_message");
logger.logStructured("test_message", {source_file: "test_log4moz.js",
message_position: 4});
let messageOne = {"_time": /\d+/,
"_namespace": "test.StructuredOutput",
"_level": "INFO",
"_message": "message string one",
"action": "test_message"};
let messageTwo = {"_time": /\d+/,
"_namespace": "test.StructuredOutput",
"_level": "ERROR",
"_message": "message string two",
"action": "test_message",
"source_file": "test_log4moz.js"};
let messageThree = {"_time": /\d+/,
"_namespace": "test.StructuredOutput",
"_level": "INFO",
"action": "test_message"};
let messageFour = {"_time": /\d+/,
"_namespace": "test.StructuredOutput",
"_level": "INFO",
"action": "test_message",
"source_file": "test_log4moz.js",
"message_position": 4};
checkObjects(messageOne, JSON.parse(appender.messages[0]));
checkObjects(messageTwo, JSON.parse(appender.messages[1]));
checkObjects(messageThree, JSON.parse(appender.messages[2]));
checkObjects(messageFour, JSON.parse(appender.messages[3]));
let errored = false;
try {
logger.logStructured("", {_message: "invalid message"});
} catch (e) {
errored = true;
do_check_eq(e, "An action is required when logging a structured message.");
} finally {
do_check_true(errored);
}
let errored = false;
try {
logger.logStructured("message_action", "invalid params");
} catch (e) {
errored = true;
do_check_eq(e, "The params argument is required to be an object.");
} finally {
do_check_true(errored);
}
// Logging with unstructured interface should produce the same messages
// as the structured interface for these cases.
let appender = new MockAppender(new Log4Moz.StructuredFormatter());
let logger = Log4Moz.repository.getLogger("test.StructuredOutput1");
messageOne._namespace = "test.StructuredOutput1";
messageTwo._namespace = "test.StructuredOutput1";
logger.addAppender(appender);
logger.level = Log4Moz.Level.All;
logger.info("message string one", {action: "test_message"});
logger.error("message string two", {action: "test_message",
source_file: "test_log4moz.js"});
checkObjects(messageOne, JSON.parse(appender.messages[0]));
checkObjects(messageTwo, JSON.parse(appender.messages[1]));
run_next_test();
});
add_test(function test_StorageStreamAppender() {
let appender = new Log4Moz.StorageStreamAppender(testFormatter);
do_check_eq(appender.getInputStream(), null);