Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2013-06-04 10:12:12 -04:00
commit 676ee5151c
22 changed files with 750 additions and 201 deletions

View File

@ -471,6 +471,8 @@
@BINPATH@/components/DOMWifiManager.manifest
@BINPATH@/components/NetworkStatsManager.js
@BINPATH@/components/NetworkStatsManager.manifest
@BINPATH@/components/NetworkInterfaceListService.manifest
@BINPATH@/components/NetworkInterfaceListService.js
#endif
#ifdef MOZ_B2G_FM
@BINPATH@/components/DOMFMRadioChild.js

View File

@ -62,7 +62,10 @@ this.BrowserNewTabPreloader = {
newTab: function Preloader_newTab(aTab) {
let win = aTab.ownerDocument.defaultView;
if (win.gBrowser) {
let {boxObject: {width, height}} = win.gBrowser;
let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let {width, height} = utils.getBoundsWithoutFlushing(win.gBrowser);
let hiddenBrowser = HiddenBrowsers.get(width, height)
if (hiddenBrowser) {
return hiddenBrowser.swapWithNewTab(aTab);

View File

@ -1540,6 +1540,35 @@ nsDOMWindowUtils::GetScrollbarSize(bool aFlushLayout, int32_t* aWidth,
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetBoundsWithoutFlushing(nsIDOMElement *aElement,
nsIDOMClientRect** aResult)
{
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
nsresult rv;
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsClientRect> rect = new nsClientRect(window);
nsIFrame* frame = content->GetPrimaryFrame();
if (frame) {
nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame,
nsLayoutUtils::GetContainingBlockForClientRect(frame),
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
rect->SetLayoutRect(r);
}
rect.forget(aResult);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetRootBounds(nsIDOMClientRect** aResult)
{

View File

@ -903,14 +903,7 @@ RunDBusCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable,
// being gtk based, sometimes we'll get signals/reply coming in on the main
// thread. There's not a lot we can do about that for the time being and it
// (technically) shouldn't hurt anything. However, on gonk, die.
// Due to the fact introducing workaround in Bug 827888, the callback for a
// message gets executed immediately. The proper fix is in bug 830290, but
// it's a intrusive change, it is better to remove assertion here since it
// would not hurt anything.
// Tracking bug 830290 for intrusive solution.
// MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!NS_IsMainThread());
#endif
nsRefPtr<BluetoothReplyRunnable> replyRunnable =
dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));

View File

@ -205,6 +205,39 @@ const CONTACT_CONTRACTID = "@mozilla.org/contact;1";
const CONTACT_CID = Components.ID("{72a5ee28-81d8-4af8-90b3-ae935396cc66}");
const nsIDOMContact = Components.interfaces.nsIDOMContact;
function checkBlobArray(aBlob) {
if (Array.isArray(aBlob)) {
for (let i = 0; i < aBlob.length; i++) {
if (typeof aBlob != 'object') {
return null;
}
if (!(aBlob[i] instanceof Components.interfaces.nsIDOMBlob)) {
return null;
}
}
return aBlob;
}
return null;
}
function isVanillaObj(aObj) {
return Object.prototype.toString.call(aObj) == "[object Object]";
}
function validateArrayField(data, createCb) {
if (data) {
data = Array.isArray(data) ? data : [data];
let filtered = [];
for (let obj of data) {
if (obj && isVanillaObj(obj)) {
filtered.push(createCb(obj));
}
}
return filtered;
}
return undefined;
}
function Contact() { };
Contact.prototype = {
@ -235,120 +268,220 @@ Contact.prototype = {
genderIdentity: 'rw'
},
set name(aName) {
this._name = sanitizeStringArray(aName);
},
get name() {
return this._name;
},
set honorificPrefix(aHonorificPrefix) {
this._honorificPrefix = sanitizeStringArray(aHonorificPrefix);
},
get honorificPrefix() {
return this._honorificPrefix;
},
set givenName(aGivenName) {
this._givenName = sanitizeStringArray(aGivenName);
},
get givenName() {
return this._givenName;
},
set additionalName(aAdditionalName) {
this._additionalName = sanitizeStringArray(aAdditionalName);
},
get additionalName() {
return this._additionalName;
},
set familyName(aFamilyName) {
this._familyName = sanitizeStringArray(aFamilyName);
},
get familyName() {
return this._familyName;
},
set honorificSuffix(aHonorificSuffix) {
this._honorificSuffix = sanitizeStringArray(aHonorificSuffix);
},
get honorificSuffix() {
return this._honorificSuffix;
},
set nickname(aNickname) {
this._nickname = sanitizeStringArray(aNickname);
},
get nickname() {
return this._nickname;
},
set photo(aPhoto) {
this._photo = checkBlobArray(aPhoto);
},
get photo() {
return this._photo;
},
set category(aCategory) {
this._category = sanitizeStringArray(aCategory);
},
get category() {
return this._category;
},
set email(aEmail) {
this._email = validateArrayField(aEmail, function(email) {
return new ContactField(email.type, email.value, email.pref);
});
},
get email() {
return this._email;
},
set adr(aAdr) {
this._adr = validateArrayField(aAdr, function(adr) {
return new ContactAddress(adr.type, adr.streetAddress, adr.locality,
adr.region, adr.postalCode, adr.countryName,
adr.pref);
});
},
get adr() {
return this._adr;
},
set tel(aTel) {
this._tel = validateArrayField(aTel, function(tel) {
return new ContactTelField(tel.type, tel.value, tel.carrier, tel.pref);
});
},
get tel() {
return this._tel;
},
set impp(aImpp) {
this._impp = validateArrayField(aImpp, function(impp) {
return new ContactField(impp.type, impp.value, impp.pref);
});
},
get impp() {
return this._impp;
},
set url(aUrl) {
this._url = validateArrayField(aUrl, function(url) {
return new ContactField(url.type, url.value, url.pref);
});
},
get url() {
return this._url;
},
set org(aOrg) {
this._org = sanitizeStringArray(aOrg);
},
get org() {
return this._org;
},
set jobTitle(aJobTitle) {
this._jobTitle = sanitizeStringArray(aJobTitle);
},
get jobTitle() {
return this._jobTitle;
},
set note(aNote) {
this._note = sanitizeStringArray(aNote);
},
get note() {
return this._note;
},
set bday(aBday) {
if (aBday !== undefined && aBday !== null) {
this._bday = new Date(aBday);
}
},
get bday() {
return this._bday;
},
set anniversary(aAnniversary) {
if (aAnniversary !== undefined && aAnniversary !== null) {
this._anniversary = new Date(aAnniversary);
}
},
get anniversary() {
return this._anniversary;
},
set sex(aSex) {
if (aSex !== "undefined") {
this._sex = aSex;
} else {
this._sex = null;
}
},
get sex() {
return this._sex;
},
set genderIdentity(aGenderIdentity) {
if (aGenderIdentity !== "undefined") {
this._genderIdentity = aGenderIdentity;
} else {
this._genderIdentity = null;
}
},
get genderIdentity() {
return this._genderIdentity;
},
init: function init(aProp) {
function _checkBlobArray(aBlob) {
if (Array.isArray(aBlob)) {
for (let i = 0; i < aBlob.length; i++) {
if (typeof aBlob != 'object') {
return null;
}
if (!(aBlob[i] instanceof Components.interfaces.nsIDOMBlob)) {
return null;
}
}
return aBlob;
}
return null;
}
function _isVanillaObj(aObj) {
return Object.prototype.toString.call(aObj) == "[object Object]";
}
let _create = sanitizeStringArray;
this.name = _create(aProp.name);
this.honorificPrefix = _create(aProp.honorificPrefix);
this.givenName = _create(aProp.givenName);
this.additionalName = _create(aProp.additionalName);
this.familyName = _create(aProp.familyName);
this.honorificSuffix = _create(aProp.honorificSuffix);
this.nickname = _create(aProp.nickname);
if (aProp.email) {
aProp.email = Array.isArray(aProp.email) ? aProp.email : [aProp.email];
this.email = new Array();
for (let email of aProp.email) {
if (_isVanillaObj(email)) {
this.email.push(new ContactField(email.type, email.value, email.pref));
} else if (DEBUG) {
debug("email field is not a ContactField and was ignored.");
}
}
} else if (DEBUG) {
this.email = null;
}
this.photo = _checkBlobArray(aProp.photo);
this.category = _create(aProp.category);
if (aProp.adr) {
aProp.adr = Array.isArray(aProp.adr) ? aProp.adr : [aProp.adr];
this.adr = new Array();
for (let adr of aProp.adr) {
if (_isVanillaObj(adr)) {
this.adr.push(new ContactAddress(adr.type, adr.streetAddress, adr.locality,
adr.region, adr.postalCode, adr.countryName,
adr.pref));
} else if (DEBUG) {
debug("adr field is not a ContactAddress and was ignored.");
}
}
} else {
this.adr = null;
}
if (aProp.tel) {
aProp.tel = Array.isArray(aProp.tel) ? aProp.tel : [aProp.tel];
this.tel = new Array();
for (let tel of aProp.tel) {
if (_isVanillaObj(tel)) {
this.tel.push(new ContactTelField(tel.type, tel.value, tel.carrier,
tel.pref));
} else if (DEBUG) {
debug("tel field is not a ContactTelField and was ignored.");
}
}
} else {
this.tel = null;
}
this.org = _create(aProp.org);
this.jobTitle = _create(aProp.jobTitle);
this.bday = (aProp.bday == undefined || aProp.bday == null) ? null : new Date(aProp.bday);
this.note = _create(aProp.note);
if (aProp.impp) {
aProp.impp = Array.isArray(aProp.impp) ? aProp.impp : [aProp.impp];
this.impp = new Array();
for (let impp of aProp.impp) {
if (_isVanillaObj(impp)) {
this.impp.push(new ContactField(impp.type, impp.value, impp.pref));
} else if (DEBUG) {
debug("impp field is not a ContactField and was ignored.");
}
}
} else {
this.impp = null;
}
if (aProp.url) {
aProp.url = Array.isArray(aProp.url) ? aProp.url : [aProp.url];
this.url = new Array();
for (let url of aProp.url) {
if (_isVanillaObj(url)) {
this.url.push(new ContactField(url.type, url.value, url.pref));
} else if (DEBUG) {
debug("url field is not a ContactField and was ignored.");
}
}
} else {
this.url = null;
}
this.anniversary = (aProp.anniversary == undefined || aProp.anniversary == null) ? null : new Date(aProp.anniversary);
this.sex = (aProp.sex != "undefined") ? aProp.sex : null;
this.genderIdentity = (aProp.genderIdentity != "undefined") ? aProp.genderIdentity : null;
this.name = aProp.name;
this.honorificPrefix = aProp.honorificPrefix;
this.givenName = aProp.givenName;
this.additionalName = aProp.additionalName;
this.familyName = aProp.familyName;
this.honorificSuffix = aProp.honorificSuffix;
this.nickname = aProp.nickname;
this.email = aProp.email;
this.photo = aProp.photo;
this.url = aProp.url;
this.category = aProp.category;
this.adr = aProp.adr;
this.tel = aProp.tel;
this.org = aProp.org;
this.jobTitle = aProp.jobTitle;
this.bday = aProp.bday;
this.note = aProp.note;
this.impp = aProp.impp;
this.anniversary = aProp.anniversary;
this.sex = aProp.sex;
this.genderIdentity = aProp.genderIdentity;
},
get published () {
@ -380,7 +513,7 @@ Contact.prototype = {
// ContactManager
const CONTACTMANAGER_CONTRACTID = "@mozilla.org/contactManager;1";
const CONTACTMANAGER_CID = Components.ID("{7bfb6481-f946-4254-afc5-d7fe9f5c45a3}");
const CONTACTMANAGER_CID = Components.ID("{8beb3a66-d70a-4111-b216-b8e995ad3aff}");
const nsIDOMContactManager = Components.interfaces.nsIDOMContactManager;
function ContactManager()
@ -525,6 +658,13 @@ ContactManager.prototype = {
Services.DOMRequest.fireSuccess(req, msg.revision);
}
break;
case "Contacts:Count":
if (DEBUG) debug("count: " + msg.count);
req = this.getRequest(msg.requestID);
if (req) {
Services.DOMRequest.fireSuccess(req, msg.count);
}
break;
default:
if (DEBUG) debug("Wrong message: " + aMessage.name);
}
@ -545,6 +685,7 @@ ContactManager.prototype = {
case "find":
case "listen":
case "revision":
case "count":
access = "read";
break;
default:
@ -734,6 +875,23 @@ ContactManager.prototype = {
return request;
},
getCount: function() {
let request = this.createRequest();
let allowCallback = function() {
cpmm.sendAsyncMessage("Contacts:GetCount", {
requestID: this.getRequestId(request)
});
}.bind(this);
let cancelCallback = function() {
Services.DOMRequest.fireError(request);
};
this.askPermission("count", request, allowCallback, cancelCallback);
return request;
},
init: function(aWindow) {
this.initHelper(aWindow, ["Contacts:Find:Return:OK", "Contacts:Find:Return:KO",
"Contacts:Clear:Return:OK", "Contacts:Clear:Return:KO",
@ -741,8 +899,8 @@ ContactManager.prototype = {
"Contact:Remove:Return:OK", "Contact:Remove:Return:KO",
"Contact:Changed",
"PermissionPromptHelper:AskPermission:OK",
"Contacts:GetAll:Next",
"Contacts:Revision"]);
"Contacts:GetAll:Next", "Contacts:Revision",
"Contacts:Count"]);
},
// Called from DOMRequestIpcHelper

View File

@ -20,6 +20,6 @@ component {72a5ee28-81d8-4af8-90b3-ae935396cc66} ContactManager.js
contract @mozilla.org/contact;1 {72a5ee28-81d8-4af8-90b3-ae935396cc66}
category JavaScript-global-constructor mozContact @mozilla.org/contact;1
component {7bfb6481-f946-4254-afc5-d7fe9f5c45a3} ContactManager.js
contract @mozilla.org/contactManager;1 {7bfb6481-f946-4254-afc5-d7fe9f5c45a3}
component {8beb3a66-d70a-4111-b216-b8e995ad3aff} ContactManager.js
contract @mozilla.org/contactManager;1 {8beb3a66-d70a-4111-b216-b8e995ad3aff}
category JavaScript-navigator-property mozContacts @mozilla.org/contactManager;1

View File

@ -727,7 +727,16 @@ ContactDB.prototype = {
this.newTxn("readonly", REVISION_STORE, function (txn, store) {
store.get(REVISION_KEY).onsuccess = function (e) {
aSuccessCb(e.target.result);
}
};
});
},
getCount: function CDB_getCount(aSuccessCb) {
if (DEBUG) debug("getCount");
this.newTxn("readonly", STORE_NAME, function (txn, store) {
store.count().onsuccess = function (e) {
aSuccessCb(e.target.result);
};
});
},

View File

@ -29,7 +29,8 @@ let ContactService = {
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
"Contacts:Clear", "Contact:Save",
"Contact:Remove", "Contacts:RegisterForMessages",
"child-process-shutdown", "Contacts:GetRevision"];
"child-process-shutdown", "Contacts:GetRevision",
"Contacts:GetCount"];
this._children = [];
this._cursors = {};
this._messages.forEach(function(msgName) {
@ -184,6 +185,19 @@ let ContactService = {
}
);
break;
case "Contacts:GetCount":
if (!this.assertPermission(aMessage, "contacts-read")) {
return null;
}
this._db.getCount(
function(count) {
mm.sendAsyncMessage("Contacts:Count", {
requestID: msg.requestID,
count: count
});
}
);
break;
case "Contacts:RegisterForMessages":
if (!aMessage.target.assertPermission("contacts-read")) {
return null;

View File

@ -137,6 +137,14 @@ function onFailure() {
}
function checkStr(str1, str2, msg) {
if (str1 ^ str2) {
ok(false, "Expected both strings to be either present or absent");
return;
}
is(str1, str2, msg);
}
function checkStrArray(str1, str2, msg) {
// comparing /[null(,null)+]/ and undefined should pass
function nonNull(e) {
return e != null;
@ -150,88 +158,71 @@ function checkStr(str1, str2, msg) {
}
function checkAddress(adr1, adr2) {
checkStr(adr1.type, adr2.type, "Same type");
checkStr(adr1.streetAddress, adr2.streetAddress, "Same streetAddress");
checkStr(adr1.locality, adr2.locality, "Same locality");
checkStr(adr1.region, adr2.region, "Same region");
checkStr(adr1.postalCode, adr2.postalCode, "Same postalCode");
checkStr(adr1.countryName, adr2.countryName, "Same countryName");
if (adr1 ^ adr2) {
ok(false, "Expected both adrs to be either present or absent");
return;
}
dump("adr1: " + adr1 + ", adr2: " + adr2 + "\n");
checkStrArray(adr1.type, adr2.type, "Same type");
checkStrArray(adr1.streetAddress, adr2.streetAddress, "Same streetAddress");
checkStrArray(adr1.locality, adr2.locality, "Same locality");
checkStrArray(adr1.region, adr2.region, "Same region");
checkStrArray(adr1.postalCode, adr2.postalCode, "Same postalCode");
checkStrArray(adr1.countryName, adr2.countryName, "Same countryName");
is(adr1.pref, adr2.pref, "Same pref");
}
function checkTel(tel1, tel2) {
checkStr(tel1.type, tel2.type, "Same type");
checkStr(tel1.value, tel2.value, "Same value");
checkStr(tel1.carrier, tel2.carrier, "Same carrier");
if (tel1 ^ tel2) {
ok(false, "Expected both tels to be either present or absent");
return;
}
checkStrArray(tel1.type, tel2.type, "Same type");
checkStrArray(tel1.value, tel2.value, "Same value");
checkStrArray(tel1.carrier, tel2.carrier, "Same carrier");
is(tel1.pref, tel2.pref, "Same pref");
}
function checkField(field1, field2) {
checkStr(field1.type, field2.type, "Same type");
checkStr(field1.value, field2.value, "Same value");
if (field1 ^ field2) {
ok(false, "Expected both fields to be either present or absent");
return;
}
checkStrArray(field1.type, field2.type, "Same type");
checkStrArray(field1.value, field2.value, "Same value");
is(field1.pref, field2.pref, "Same pref");
}
function checkContacts(contact1, contact2) {
checkStr(contact1.name, contact2.name, "Same name");
checkStr(contact1.honorificPrefix, contact2.honorificPrefix, "Same honorificPrefix");
checkStr(contact1.givenName, contact2.givenName, "Same givenName");
checkStr(contact1.additionalName, contact2.additionalName, "Same additionalName");
checkStr(contact1.familyName, contact2.familyName, "Same familyName");
checkStr(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
checkStr(contact1.nickname, contact2.nickname, "Same nickname");
checkStr(contact1.category, contact2.category, "Same category");
checkStr(contact1.org, contact2.org, "Same org");
checkStr(contact1.jobTitle, contact2.jobTitle, "Same jobTitle");
checkStrArray(contact1.name, contact2.name, "Same name");
checkStrArray(contact1.honorificPrefix, contact2.honorificPrefix, "Same honorificPrefix");
checkStrArray(contact1.givenName, contact2.givenName, "Same givenName");
checkStrArray(contact1.additionalName, contact2.additionalName, "Same additionalName");
checkStrArray(contact1.familyName, contact2.familyName, "Same familyName");
checkStrArray(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
checkStrArray(contact1.nickname, contact2.nickname, "Same nickname");
checkStrArray(contact1.category, contact2.category, "Same category");
checkStrArray(contact1.org, contact2.org, "Same org");
checkStrArray(contact1.jobTitle, contact2.jobTitle, "Same jobTitle");
is(contact1.bday ? contact1.bday.valueOf() : null, contact2.bday ? contact2.bday.valueOf() : null, "Same birthday");
checkStr(contact1.note, contact2.note, "Same note");
checkStrArray(contact1.note, contact2.note, "Same note");
is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
is(contact1.sex, contact2.sex, "Same sex");
is(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
checkStr(contact1.sex, contact2.sex, "Same sex");
checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
for (var i in contact1.email) {
if (contact1.email) {
ok(contact2.email != null, "conatct2.email exists");
}
if (contact2.email) {
ok(contact1.email != null, "conatct1.email exists");
}
checkField(contact1.email[i], contact2.email[i]);
}
for (var i in contact1.adr) {
if (contact1.adr) {
ok(contact2.adr != null, "conatct2.adr exists");
}
if (contact2.adr) {
ok(contact1.adr != null, "conatct1.adr exists");
}
checkAddress(contact1.adr[i], contact2.adr[i]);
}
for (var i in contact1.tel) {
if (contact1.tel) {
ok(contact2.tel != null, "conatct2.tel exists");
}
if (contact2.tel) {
ok(contact1.tel != null, "conatct1.tel exists");
}
checkTel(contact1.tel[i], contact2.tel[i]);
}
for (var i in contact1.url) {
if (contact1.url) {
ok(contact2.url != null, "conatct2.url exists");
}
if (contact2.url) {
ok(contact1.url != null, "conatct1.url exists");
}
checkField(contact1.url[i], contact2.url[i]);
}
for (var i in contact1.impp) {
if (contact1.impp) {
ok(contact2.impp != null, "conatct2.impp exists");
}
if (contact2.impp) {
ok(contact1.impp != null, "conatct1.impp exists");
}
checkField(contact1.impp[i], contact2.impp[i]);
}
}
@ -250,6 +241,15 @@ function checkRevision(revision, msg, then) {
revReq.onerror = onFailure;
}
function checkCount(count, msg, then) {
var request = navigator.mozContacts.getCount();
request.onsuccess = function(e) {
is(e.target.result, count, msg);
then();
};
request.onerror = onFailure;
}
var mozContacts = window.navigator.mozContacts;
ok(mozContacts, "mozContacts exists");
ok("mozContact" in window, "mozContact exists");
@ -266,7 +266,9 @@ var steps = [
req = mozContacts.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
checkRevision(1, "Revision was incremented on clear", next);
checkCount(0, "No contacts after clear", function() {
checkRevision(1, "Revision was incremented on clear", next);
});
};
req.onerror = onFailure;
});
@ -288,7 +290,9 @@ var steps = [
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
checkRevision(2, "Revision was incremented on save", next);
checkCount(1, "1 contact after adding empty contact", function() {
checkRevision(2, "Revision was incremented on save", next);
});
};
req.onerror = onFailure;
},
@ -331,7 +335,7 @@ var steps = [
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
checkContacts(properties1, createResult1);
checkContacts(createResult1, properties1);
};
req.onerror = onFailure;
},
@ -498,7 +502,7 @@ var steps = [
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
checkContacts(properties1, createResult1);
checkContacts(createResult1, properties1);
next();
};
req.onerror = onFailure;
@ -999,7 +1003,7 @@ var steps = [
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
ok(createResult1.name == properties1.name, "Same Name");
next();
checkCount(20, "20 contacts in DB", next);
};
req.onerror = onFailure;
},
@ -1091,7 +1095,7 @@ var steps = [
req = mozContacts.save(cloned);
req.onsuccess = function () {
ok(cloned.id, "The contact now has an ID.");
ok(cloned.email.value == "new email!", "Same Email");
ok(cloned.email[0].value == "new email!", "Same Email");
ok(createResult1.email != cloned.email, "Clone has different email");
ok(cloned.givenName == "Tom", "New Name");
next();
@ -1255,7 +1259,7 @@ var steps = [
var req2 = mozContacts.find(options);
req2.onsuccess = function() {
is(req2.result.length, 1, "1 Entry");
checkStr(req2.result.givenName, "customTest", "same name");
checkStrArray(req2.result.givenName, "customTest", "same name");
ok(req2.result.yyy === undefined, "custom property undefined");
next();
}
@ -1430,6 +1434,23 @@ var steps = [
}
req.onerror = onFailure;
},
function() {
ok(true, "Test setting array properties to scalar values")
const DOMStrings = ["name","honorificPrefix","givenName","additionalName",
"familyName", "honorificSuffix","nickname","category",
"org","jobTitle","note"];
const FIELDS = ["email","url","adr","tel","impp"];
createResult1 = new mozContact();
for (var prop of DOMStrings) {
createResult1[prop] = "foo";
ok(Array.isArray(createResult1[prop]), prop + " is array");
}
for (var prop of FIELDS) {
createResult1[prop] = {type: "foo"};
ok(Array.isArray(createResult1[prop]), prop + " is array");
}
next();
},
function () {
ok(true, "all done!\n");
clearTemps();
@ -1445,11 +1466,11 @@ function next() {
return;
}
try {
steps[index]();
var i = index++;
steps[i]();
} catch(ex) {
ok(false, "Caught exception", ex);
}
index += 1;
}
SimpleTest.waitForExplicitFinish();

View File

@ -42,7 +42,7 @@ interface nsIURI;
interface nsIDOMEventTarget;
interface nsIRunnable;
[scriptable, uuid(dba80826-6251-4947-bf2a-a3873b9ec764)]
[scriptable, uuid(a806d366-cc52-11e2-bc9a-ba3212c84021)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -658,6 +658,11 @@ interface nsIDOMWindowUtils : nsISupports {
*/
void getScrollbarSize(in boolean aFlushLayout, out long aWidth, out long aHeight);
/**
* Returns the given element's bounds without flushing pending layout changes.
*/
nsIDOMClientRect getBoundsWithoutFlushing(in nsIDOMElement aElement);
/**
* Returns the bounds of the window's currently loaded document. This will
* generally be (0, 0, pageWidth, pageHeight) but in some cases (e.g. RTL

View File

@ -20,7 +20,7 @@ interface nsIDOMContact : nsIContactProperties
void init(in nsIContactProperties properties); // Workaround BUG 723206
};
[scriptable, uuid(e01ebfe7-e972-4e01-b04b-1d162dc74983)]
[scriptable, uuid(8beb3a66-d70a-4111-b216-b8e995ad3aff)]
interface nsIDOMContactManager : nsISupports
{
nsIDOMDOMRequest find(in nsIContactFindOptions options);
@ -36,4 +36,6 @@ interface nsIDOMContactManager : nsISupports
attribute nsIDOMEventListener oncontactchange;
nsIDOMDOMRequest getRevision();
nsIDOMDOMRequest getCount();
};

View File

@ -1263,7 +1263,8 @@ MmsService.prototype = {
this.retrieveMessage(url,
this.retrieveMessageCallback.bind(this,
wish,
savableMessage));
savableMessage),
domMessage);
},
/**
@ -1294,8 +1295,7 @@ MmsService.prototype = {
.saveReceivedMessage(savableMessage,
this.saveReceivedMessageCallback.bind(this,
retrievalMode,
savableMessage),
domMessage);
savableMessage));
}).bind(this));
},
@ -1476,7 +1476,7 @@ MmsService.prototype = {
retrieve: function retrieve(aMessageId, aRequest) {
if (DEBUG) debug("Retrieving message with ID " + aMessageId);
gMobileMessageDatabaseService.getMessageRecordById(aMessageId,
(function notifyResult(aRv, aMessageRecord) {
(function notifyResult(aRv, aMessageRecord, aDomMessage) {
if (Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR != aRv) {
if (DEBUG) debug("Function getMessageRecordById() return error.");
aRequest.notifyGetMessageFailed(aRv);
@ -1526,10 +1526,17 @@ MmsService.prototype = {
let wish = aMessageRecord.headers["x-mms-delivery-report"];
let responseNotify = function responseNotify(mmsStatus, retrievedMsg) {
// If the mmsStatus is still MMS_PDU_STATUS_DEFERRED after retry,
// we should not store it into database.
// we should not store it into database and update its delivery
// status to 'error'.
if (MMS.MMS_PDU_STATUS_RETRIEVED !== mmsStatus) {
if (DEBUG) debug("RetrieveMessage fail after retry.");
aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
gMobileMessageDatabaseService.setMessageDelivery(aMessageId,
null,
null,
DELIVERY_STATUS_ERROR,
function () {
aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
});
return;
}
// In OMA-TS-MMS_ENC-V1_3, Table 5 in page 25. This header field
@ -1585,7 +1592,9 @@ MmsService.prototype = {
null,
null,
DELIVERY_STATUS_PENDING,
this.retrieveMessage(url, responseNotify.bind(this)));
this.retrieveMessage(url,
responseNotify.bind(this),
aDomMessage));
}).bind(this));
},

View File

@ -43,6 +43,8 @@ EXTRA_COMPONENTS = \
RadioInterfaceLayer.manifest \
RadioInterfaceLayer.js \
RILContentHelper.js \
NetworkInterfaceListService.manifest \
NetworkInterfaceListService.js \
$(NULL)
EXTRA_JS_MODULES = \

View File

@ -0,0 +1,63 @@
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const NETWORKLISTSERVICE_CONTRACTID =
"@mozilla.org/network/interface-list-service;1";
const NETWORKLISTSERVICE_CID =
Components.ID("{3780be6e-7012-4e53-ade6-15212fb88a0d}");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsISyncMessageSender");
function NetworkInterfaceListService () {
}
NetworkInterfaceListService.prototype = {
classID: NETWORKLISTSERVICE_CID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterfaceListService]),
getDataInterfaceList: function(aConditions) {
return new NetworkInterfaceList(
cpmm.sendSyncMessage(
'NetworkInterfaceList:ListInterface',
{
excludeSupl: (aConditions &
Ci.nsINetworkInterfaceListService.
LIST_NOT_INCLUDE_SUPL_INTERFACES) != 0,
excludeMms: (aConditions &
Ci.nsINetworkInterfaceListService.
LIST_NOT_INCLUDE_MMS_INTERFACES) != 0
}
)[0]);
}
};
function NetworkInterfaceList (aInterfaces) {
this._interfaces = aInterfaces;
}
NetworkInterfaceList.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterfaceList]),
getNumberOfInterface: function() {
return this._interfaces.length;
},
getInterface: function(index) {
if (!this._interfaces) {
return null;
}
return this._interfaces[index];
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkInterfaceListService]);

View File

@ -0,0 +1,17 @@
# Copyright 2012 Mozilla Foundation and Mozilla contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# NetworkInterfaceListService.js
component {3780be6e-7012-4e53-ade6-15212fb88a0d} NetworkInterfaceListService.js
contract @mozilla.org/network/interface-list-service;1 {3780be6e-7012-4e53-ade6-15212fb88a0d}

View File

@ -22,6 +22,10 @@ const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
"@mozilla.org/settingsService;1",
"nsISettingsService");
XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
return Cc["@mozilla.org/parentprocessmessagemanager;1"]
.getService(Ci.nsIMessageBroadcaster);
});
XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
"@mozilla.org/network/dns-service;1",
@ -210,6 +214,8 @@ function NetworkManager() {
debug("Error reading the 'tethering.wifi.enabled' setting: " + aErrorMessage);
}
});
ppmm.addMessageListener('NetworkInterfaceList:ListInterface', this);
}
NetworkManager.prototype = {
classID: NETWORKMANAGER_CID,
@ -320,6 +326,38 @@ NetworkManager.prototype = {
}
},
receiveMessage: function receiveMessage(aMsg) {
switch (aMsg.name) {
case "NetworkInterfaceList:ListInterface": {
let excludeMms = aMsg.json.exculdeMms;
let excludeSupl = aMsg.json.exculdeSupl;
let interfaces = [];
for each (let i in this.networkInterfaces) {
if ((i.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS && excludeMms) ||
(i.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL && excludeSupl)) {
continue;
}
interfaces.push({
state: i.state,
type: i.type,
name: i.name,
dhcp: i.dhcp,
ip: i.ip,
netmask: i.netmask,
broadcast: i.broadcast,
gateway: i.gateway,
dns1: i.dns1,
dns2: i.dns2,
httpProxyHost: i.httpProxyHost,
httpProxyPort: i.httpProxyPort
});
}
return interfaces;
}
}
},
// nsINetworkManager
registerNetworkInterface: function registerNetworkInterface(network) {

View File

@ -17,6 +17,7 @@
XPIDL_SOURCES += [
'nsIAudioManager.idl',
'nsINavigatorAudioChannelManager.idl',
'nsINetworkInterfaceListService.idl',
'nsINetworkManager.idl',
'nsIRadioInterfaceLayer.idl',
'nsISystemWorkerManager.idl',

View File

@ -0,0 +1,36 @@
/* 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 "nsINetworkManager.idl"
#include "nsISupports.idl"
[scriptable, uuid(b44d74db-c9d6-41dd-98ae-a56918d6e6ad)]
interface nsINetworkInterfaceList : nsISupports
{
/**
* Number of the network interfaces that is available.
*/
long getNumberOfInterface();
/**
* Get the i-th interface from the list.
* @param interfaceIndex index of interface, from 0 to number of interface - 1.
*/
nsINetworkInterface getInterface(in long interfaceIndex);
};
[scriptable, uuid(5be50bcb-bfe9-4742-b7e6-3e9bb4835369)]
interface nsINetworkInterfaceListService : nsISupports
{
const long LIST_NOT_INCLUDE_MMS_INTERFACES = 1;
const long LIST_NOT_INCLUDE_SUPL_INTERFACES = 2;
/**
* Obtain a list of network interfaces that satisfy the specified condition.
* @param condition flags that specify the interfaces to be returned. This
* can be OR combination of LIST_* flags, or zero to make all available
* interfaces returned.
*/
nsINetworkInterfaceList getDataInterfaceList(in long condition);
};

View File

@ -0,0 +1,129 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
extern "C" {
#include <arpa/inet.h>
#include "r_types.h"
#include "stun.h"
#include "addrs.h"
}
#include <vector>
#include <string>
#include "nsINetworkManager.h"
#include "nsINetworkInterfaceListService.h"
#include "runnable_utils.h"
#include "nsCOMPtr.h"
#include "nsThreadUtils.h"
#include "nsServiceManagerUtils.h"
namespace {
struct NetworkInterface {
struct sockaddr_in addr;
std::string name;
};
nsresult
GetInterfaces(std::vector<NetworkInterface>* aInterfaces)
{
MOZ_ASSERT(aInterfaces);
// Obtain network interfaces from network manager.
nsresult rv;
nsCOMPtr<nsINetworkInterfaceListService> listService =
do_GetService("@mozilla.org/network/interface-list-service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
int32_t flags =
nsINetworkInterfaceListService::LIST_NOT_INCLUDE_SUPL_INTERFACES |
nsINetworkInterfaceListService::LIST_NOT_INCLUDE_MMS_INTERFACES;
nsCOMPtr<nsINetworkInterfaceList> networkList;
NS_ENSURE_SUCCESS(listService->GetDataInterfaceList(flags,
getter_AddRefs(networkList)),
NS_ERROR_FAILURE);
// Translate nsINetworkInterfaceList to NetworkInterface.
int32_t listLength;
NS_ENSURE_SUCCESS(networkList->GetNumberOfInterface(&listLength),
NS_ERROR_FAILURE);
aInterfaces->clear();
nsAutoString ip;
nsAutoString ifaceName;
for (int32_t i = 0; i < listLength; i++) {
nsCOMPtr<nsINetworkInterface> iface;
if (NS_FAILED(networkList->GetInterface(i, getter_AddRefs(iface)))) {
continue;
}
NetworkInterface interface;
memset(&(interface.addr), 0, sizeof(interface.addr));
interface.addr.sin_family = AF_INET;
if (NS_FAILED(iface->GetIp(ip))) {
continue;
}
if (inet_pton(AF_INET, NS_ConvertUTF16toUTF8(ip).get(),
&(interface.addr.sin_addr.s_addr)) != 1) {
continue;
}
if (NS_FAILED(iface->GetName(ifaceName))) {
continue;
}
interface.name = NS_ConvertUTF16toUTF8(ifaceName).get();
aInterfaces->push_back(interface);
}
return NS_OK;
}
} // anonymous namespace
int
nr_stun_get_addrs(nr_transport_addr aAddrs[], int aMaxAddrs,
int aDropLoopback, int* aCount)
{
nsresult rv;
int r;
// Get network interface list.
std::vector<NetworkInterface> interfaces;
if (NS_FAILED(NS_DispatchToMainThread(
mozilla::WrapRunnableNMRet(&GetInterfaces, &interfaces, &rv),
NS_DISPATCH_SYNC))) {
return R_FAILED;
}
if (NS_FAILED(rv)) {
return R_FAILED;
}
// Translate to nr_transport_addr.
int32_t n = 0;
size_t num_interface = std::min(interfaces.size(), (size_t)aMaxAddrs);
for (size_t i = 0; i < num_interface; ++i) {
NetworkInterface &interface = interfaces[i];
if (nr_sockaddr_to_transport_addr((sockaddr*)&(interface.addr),
sizeof(struct sockaddr_in),
IPPROTO_UDP, 0, &(aAddrs[n]))) {
r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
return R_FAILED;
}
strlcpy(aAddrs[n].ifname, interface.name.c_str(), sizeof(aAddrs[n].ifname));
n++;
}
*aCount = n;
r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aCount);
if (r != 0) {
return r;
}
for (int i = 0; i < *aCount; ++i) {
r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s", i,
aAddrs[i].as_string, aAddrs[i].ifname);
}
return 0;
}

View File

@ -79,5 +79,11 @@ MTRANSPORT_LCPPSRCS = \
transportlayerprsock.cpp \
$(NULL)
ifdef MOZ_B2G_RIL
MTRANSPORT_LCPPSRCS += \
gonk_addrs.cpp \
$(NULL)
endif
MTRANSPORT_CPPSRCS = $(addprefix $(topsrcdir)/media/mtransport/, $(MTRANSPORT_LCPPSRCS))

View File

@ -6,6 +6,9 @@
#
#
{
'variables' : {
'build_with_gonk%': 0,
},
'targets' : [
{
'target_name' : 'nicer',
@ -213,6 +216,12 @@
'NO_REG_RPC',
],
}],
# Gonk has its own nr_stun_get_addrs implementation.
['build_with_gonk==1', {
'defines': [
"USE_PLATFORM_NR_STUN_GET_ADDRS",
]
}]
],
}]
}

View File

@ -687,6 +687,8 @@ nr_stun_remove_duplicate_addrs(nr_transport_addr addrs[], int remove_loopback, i
return _status;
}
#ifndef USE_PLATFORM_NR_STUN_GET_ADDRS
int
nr_stun_get_addrs(nr_transport_addr addrs[], int maxaddrs, int drop_loopback, int *count)
{
@ -712,3 +714,4 @@ nr_stun_get_addrs(nr_transport_addr addrs[], int maxaddrs, int drop_loopback, in
return _status;
}
#endif