This commit is contained in:
Ryan VanderMeulen 2013-04-17 12:46:40 -04:00
Родитель b53f213e98 7980fe20b0
Коммит 88f55b543c
6 изменённых файлов: 156 добавлений и 63 удалений

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

@ -415,7 +415,7 @@ UpdatePrompt.prototype = {
// for the user to press Later or Install Now. In this situation we
// don't want to clear this._update, becuase handleApplyPromptResult
// needs it.
if (this._applyPromptTimer == null) {
if (this._applyPromptTimer == null && !this._waitingForIdle) {
this._update = null;
}
break;

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

@ -20,10 +20,16 @@ XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() {
return Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService);
});
XPCOMUtils.defineLazyServiceGetter(this, "pm",
"@mozilla.org/permissionmanager;1",
"nsIPermissionManager");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
const CONTACTS_SENDMORE_MINIMUM = 5;
function stringOrBust(aObj) {
if (typeof aObj != "string") {
if (DEBUG) debug("Field is not a string and was ignored.");
@ -559,6 +565,15 @@ ContactManager.prototype = {
access = "unknown";
}
// Shortcut for ALLOW_ACTION so we avoid a parent roundtrip
let type = "contacts-" + access;
let permValue =
pm.testExactPermissionFromPrincipal(this._window.document.nodePrincipal, type);
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
aAllowCallback();
return;
}
let requestID = this.getRequestId({
request: aRequest,
allow: function() {
@ -684,6 +699,9 @@ ContactManager.prototype = {
if (DEBUG) debug("contact in cache");
let contact = data.cachedContacts.shift();
this.nextTick(this._fireSuccessOrDone.bind(this, data.cursor, contact));
if (data.cachedContacts.length < CONTACTS_SENDMORE_MINIMUM) {
cpmm.sendAsyncMessage("Contacts:GetAll:SendNow", { cursorId: aCursorId });
}
} else {
if (DEBUG) debug("waiting for contact");
data.waitingForNext = true;

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

@ -23,6 +23,64 @@ const DB_VERSION = 8;
const STORE_NAME = "contacts";
const SAVED_GETALL_STORE_NAME = "getallcache";
const CHUNK_SIZE = 20;
const CHUNK_INTERVAL = 500;
function ContactDispatcher(aContacts, aFullContacts, aCallback, aNewTxn, aClearDispatcher) {
this.nextIndex = 0;
this.cancelTimeout = function() {
if (this.interval) {
clearTimeout(this.interval);
this.interval = null;
}
};
if (aFullContacts) {
this.sendChunk = function() {
if (aContacts.length > 0) {
aCallback(aContacts.splice(0, CHUNK_SIZE));
this.interval = setTimeout(this.sendChunk, CHUNK_INTERVAL);
} else {
aCallback(null);
this.cancelTimeout();
aClearDispatcher();
}
}.bind(this);
} else {
this.count = 0;
this.sendChunk = function() {
let chunk = [];
aNewTxn("readonly", STORE_NAME, function(txn, store) {
for (let i = this.nextIndex; i < Math.min(this.nextIndex+CHUNK_SIZE, aContacts.length); ++i) {
store.get(aContacts[i]).onsuccess = function(e) {
chunk.push(e.target.result);
this.count++;
if (this.count == aContacts.length) {
aCallback(chunk)
aCallback(null);
this.cancelTimeout();
aClearDispatcher();
} else if (chunk.length == CHUNK_SIZE) {
aCallback(chunk);
chunk.length = 0;
this.nextIndex += CHUNK_SIZE;
this.interval = setTimeout(this.sendChunk, CHUNK_INTERVAL);
}
}.bind(this);
}
}.bind(this));
}.bind(this);
}
this.sendChunk(0);
}
ContactDispatcher.prototype = {
sendNow: function() {
this.cancelTimeout();
this.interval = setTimeout(this.sendChunk, 0);
}
};
this.ContactDB = function ContactDB(aGlobal) {
if (DEBUG) debug("Constructor");
@ -32,6 +90,8 @@ this.ContactDB = function ContactDB(aGlobal) {
ContactDB.prototype = {
__proto__: IndexedDBHelper.prototype,
_dispatcher: {},
upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
if (DEBUG) debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
let db = aDb;
@ -513,45 +573,31 @@ ContactDB.prototype = {
}.bind(this));
},
getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions) {
sendNow: function CDB_sendNow(aCursorId) {
if (aCursorId in this._dispatcher) {
this._dispatcher[aCursorId].sendNow();
}
},
_clearDispatcher: function CDB_clearDispatcher(aCursorId) {
if (aCursorId in this._dispatcher) {
delete this._dispatcher[aCursorId];
}
},
getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions, aCursorId) {
if (DEBUG) debug("getAll")
let optionStr = JSON.stringify(aOptions);
this.getCacheForQuery(optionStr, function(aCachedResults, aFullContacts) {
// aFullContacts is true if the cache didn't exist and had to be created.
// In that case, we receive the full contacts since we already have them
// in memory to create the cache anyway. This allows us to avoid accessing
// the main object store again.
// in memory to create the cache. This allows us to avoid accessing the
// object store again.
if (aCachedResults && aCachedResults.length > 0) {
if (DEBUG) debug("query returned " + aCachedResults.length + " contacts");
if (aFullContacts) {
if (DEBUG) debug("full contacts: " + aCachedResults.length);
while(aCachedResults.length) {
aSuccessCb(aCachedResults.splice(0, CHUNK_SIZE));
}
aSuccessCb(null);
} else {
let count = 0;
let sendChunk = function(start) {
let chunk = [];
this.newTxn("readonly", STORE_NAME, function(txn, store) {
for (let i = start; i < Math.min(start+CHUNK_SIZE, aCachedResults.length); ++i) {
store.get(aCachedResults[i]).onsuccess = function(e) {
chunk.push(e.target.result);
count++;
if (count == aCachedResults.length) {
aSuccessCb(chunk);
aSuccessCb(null);
} else if (chunk.length == CHUNK_SIZE) {
aSuccessCb(chunk);
chunk.length = 0;
setTimeout(sendChunk.bind(this, start+CHUNK_SIZE), 0);
}
};
}
});
}.bind(this);
sendChunk(0);
}
let newTxnFn = this.newTxn.bind(this);
let clearDispatcherFn = this._clearDispatcher.bind(this, aCursorId);
this._dispatcher[aCursorId] = new ContactDispatcher(aCachedResults, aFullContacts,
aSuccessCb, newTxnFn, clearDispatcherFn);
} else { // no contacts
if (DEBUG) debug("query returned no contacts");
aSuccessCb(null);

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

@ -39,7 +39,8 @@ let myGlobal = this;
let ContactService = {
init: function() {
if (DEBUG) debug("Init");
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:Clear", "Contact:Save",
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
"Contacts:Clear", "Contact:Save",
"Contact:Remove", "Contacts:GetSimContacts",
"Contacts:RegisterForMessages", "child-process-shutdown"];
this._children = [];
@ -116,7 +117,12 @@ let ContactService = {
mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contacts: aContacts});
},
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { errorMsg: aErrorMsg }); },
msg.findOptions);
msg.findOptions, msg.cursorId);
break;
case "Contacts:GetAll:SendNow":
// sendNow is a no op if there isn't an existing cursor in the DB, so we
// don't need to assert the permission again.
this._db.sendNow(msg.cursorId);
break;
case "Contact:Save":
if (msg.options.reason === "create") {

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

@ -59,8 +59,16 @@ function onFailure() {
}
function checkStr(str1, str2, msg) {
if (str1)
ok(typeof str1 == "string" ? [str1] : str1, (typeof str2 == "string") ? [str2] : str2, msg);
// comparing /[null(,null)+]/ and undefined should pass
function nonNull(e) {
return e != null;
}
if ((Array.isArray(str1) && str1.filter(nonNull).length == 0 && str2 == undefined)
||(Array.isArray(str2) && str2.filter(nonNull).length == 0 && str1 == undefined)) {
ok(true, msg);
} else if (str1) {
is(JSON.stringify(typeof str1 == "string" ? [str1] : str1), JSON.stringify(typeof str2 == "string" ? [str2] : str2), msg);
}
}
function checkAddress(adr1, adr2) {
@ -157,10 +165,11 @@ function clearDatabase() {
req.onerror = onFailure;
}
function add20Contacts() {
ok(true, "Adding 20 contacts");
for (let i=0; i<19; i++) {
function addContacts() {
ok(true, "Adding 40 contacts");
for (let i = 0; i < 39; ++i) {
createResult1 = new mozContact();
properties1.familyName[0] = "Testname" + (i < 10 ? "0" + i : i);
createResult1.init(properties1);
req = mozContacts.save(createResult1);
req.onsuccess = function() {
@ -169,6 +178,7 @@ function add20Contacts() {
req.onerror = onFailure;
};
createResult1 = new mozContact();
properties1.familyName[0] = "Testname39";
createResult1.init(properties1);
req = mozContacts.save(createResult1);
req.onsuccess = function() {
@ -216,19 +226,27 @@ let steps = [
},
clearDatabase,
add20Contacts,
addContacts,
function() {
ok(true, "Retrieving 20 contacts with getAll");
req = mozContacts.getAll({});
ok(true, "Retrieving 40 contacts with getAll");
req = mozContacts.getAll({
sortBy: "familyName",
sortOrder: "ascending"
});
let count = 0;
let result;
let props;
req.onsuccess = function(event) {
if (req.result) {
ok(true, "result is valid");
result = req.result;
properties1.familyName[0] = "Testname" + (count < 10 ? "0" + count : count);
is(result.familyName[0], properties1.familyName[0], "Same familyName");
count++;
req.continue();
} else {
is(count, 20, "last contact - 20 contacts returned");
is(count, 40, "last contact - 40 contacts returned");
next();
}
};
@ -253,7 +271,7 @@ let steps = [
count++;
req.continue();
} else {
is(count, 19, "last contact - 19 contacts returned");
is(count, 39, "last contact - 39 contacts returned");
next();
}
};
@ -261,7 +279,7 @@ let steps = [
},
clearDatabase,
add20Contacts,
addContacts,
function() {
ok(true, "Test cache consistency when deleting contact during getAll");
@ -288,7 +306,7 @@ let steps = [
count++;
req.continue();
} else {
is(count, 20, "last contact - 20 contacts returned");
is(count, 40, "last contact - 40 contacts returned");
next();
}
}
@ -297,7 +315,7 @@ let steps = [
},
clearDatabase,
add20Contacts,
addContacts,
function() {
ok(true, "Delete the current contact while iterating");
@ -318,14 +336,14 @@ let steps = [
req.continue();
};
} else {
is(count, 20, "returned 20 contacts");
is(count, 40, "returned 40 contacts");
next();
}
};
},
clearDatabase,
add20Contacts,
addContacts,
function() {
ok(true, "Iterating through the contact list inside a cursor callback");
@ -341,7 +359,7 @@ let steps = [
count2++;
req2.continue();
} else {
is(count2, 20, "inner cursor returned 20 contacts");
is(count2, 40, "inner cursor returned 40 contacts");
req1.continue();
}
};
@ -350,7 +368,7 @@ let steps = [
count1++;
req1.continue();
} else {
is(count1, 20, "outer cursor returned 20 contacts");
is(count1, 40, "outer cursor returned 40 contacts");
next();
}
}
@ -358,7 +376,7 @@ let steps = [
},
clearDatabase,
add20Contacts,
addContacts,
function() {
ok(true, "20 concurrent cursors");
@ -373,7 +391,7 @@ let steps = [
count++;
req.continue();
} else {
is(count, 20, "cursor " + i + " returned 20 contacts");
is(count, 40, "cursor " + i + " returned 40 contacts");
if (++completed == NUM_CURSORS) {
next();
}

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

@ -164,13 +164,13 @@ XPCOMUtils.defineLazyGetter(this, "gMmsConnection", function () {
},
/**
* Return the roaming status of data connection.
* Return the roaming status of voice call.
*
* @return true if data connection is roaming.
* @return true if voice call is roaming.
*/
isDataConnRoaming: function isDataConnRoaming() {
let isRoaming = gRIL.rilContext.data.roaming;
debug("isDataConnRoaming = " + isRoaming);
isVoiceRoaming: function isVoiceRoaming() {
let isRoaming = gRIL.rilContext.voice.roaming;
debug("isVoiceRoaming = " + isRoaming);
return isRoaming;
},
@ -1166,9 +1166,14 @@ MmsService.prototype = {
retrievalMode = Services.prefs.getCharPref(PREF_RETRIEVAL_MODE);
} catch (e) {}
let isRoaming = gMmsConnection.isDataConnRoaming();
if ((retrievalMode === RETRIEVAL_MODE_AUTOMATIC_HOME && isRoaming) ||
RETRIEVAL_MODE_MANUAL === retrievalMode ||
// In roaming environment, we send notify response only in
// automatic retrieval mode.
if ((retrievalMode !== RETRIEVAL_MODE_AUTOMATIC) &&
gMmsConnection.isVoiceRoaming()) {
return;
}
if (RETRIEVAL_MODE_MANUAL === retrievalMode ||
RETRIEVAL_MODE_NEVER === retrievalMode) {
let mmsStatus = RETRIEVAL_MODE_NEVER === retrievalMode
? MMS.MMS_PDU_STATUS_REJECTED