merge b2g-inbound to mozilla-central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 04 Dec 2013 09:47:17 +0100
changeset 174376 9688476c1544689573c7d3ef805fd61c2fc0f631
parent 174366 9fe5e212fa41e6f9d85abea50467003301509b42 (current diff)
parent 174375 d997913037df89a04960346a36de1860425d6458 (diff)
child 174377 5fb0eb7916d2ba00c9b3559b0d7f9d06a2cf3d7d
child 174378 e55e2e773ae677155175e56e8765eae2086f9e80
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
9688476c1544 / 28.0a1 / 20131204030203 / files
nightly linux64
9688476c1544 / 28.0a1 / 20131204030203 / files
nightly mac
9688476c1544 / 28.0a1 / 20131204030203 / files
nightly win32
9688476c1544 / 28.0a1 / 20131204030203 / files
nightly win64
9688476c1544 / 28.0a1 / 20131204030203 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge b2g-inbound to mozilla-central
--- a/b2g/components/FilePicker.js
+++ b/b2g/components/FilePicker.js
@@ -98,17 +98,20 @@ FilePicker.prototype = {
     if (filterMask & Ci.nsIFilePicker.filterVideo) {
       this.mFilterTypes = this.mFilterTypes.concat(VIDEO_FILTERS);
     }
 
     if (filterMask & Ci.nsIFilePicker.filterAudio) {
       this.mFilterTypes = this.mFilterTypes.concat(AUDIO_FILTERS);
     }
 
-    // Ci.nsIFilePicker.filterAll is by default
+    if (filterMask & Ci.nsIFilePicker.filterAll) {
+      // This property is needed for the gallery app pick activity.
+      this.mExtraProps['nocrop'] = true;
+    }
   },
 
   appendFilter: function(title, extensions) {
     // pick activity doesn't support extensions
   },
 
   open: function(aFilePickerShownCallback) {
     this.mFilePickerShownCallback = aFilePickerShownCallback;
--- a/dom/contacts/tests/mochitest.ini
+++ b/dom/contacts/tests/mochitest.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 
+[shared.js]
 [test_contacts_basics.html]
 [test_contacts_basics2.html]
 [test_contacts_blobs.html]
 [test_contacts_events.html]
 [test_contacts_getall.html]
 [test_contacts_getall2.html]
 [test_contacts_international.html]
 [test_contacts_substringmatching.html]
new file mode 100644
--- /dev/null
+++ b/dom/contacts/tests/shared.js
@@ -0,0 +1,416 @@
+"use strict";
+
+// Fix the environment to run Contacts tests
+if (SpecialPowers.isMainProcess()) {
+  SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
+  SpecialPowers.Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
+}
+
+SpecialPowers.addPermission("contacts-write", true, document);
+SpecialPowers.addPermission("contacts-read", true, document);
+SpecialPowers.addPermission("contacts-create", true, document);
+
+// Some helpful global vars
+var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
+
+var defaultOptions = {
+  sortBy: "givenName",
+};
+
+var mozContacts = navigator.mozContacts;
+
+// To test sorting
+var c1 = {
+  name: ["a a"],
+  familyName: ["a"],
+  givenName: ["a"],
+};
+
+var c2 = {
+  name: ["b b"],
+  familyName: ["b"],
+  givenName: ["b"],
+};
+
+var c3 = {
+  name: ["c c", "a a", "b b"],
+  familyName: ["c","a","b"],
+  givenName: ["c","a","b"],
+};
+
+var c4 = {
+  name: ["c c", "a a", "c c"],
+  familyName: ["c","a","c"],
+  givenName: ["c","a","c"],
+};
+
+var c5 = {
+  familyName: [],
+  givenName: [],
+};
+
+var c6 = {
+  name: ["e"],
+  familyName: ["e","e","e"],
+  givenName: ["e","e","e"],
+};
+
+var c7 = {
+  name: ["e"],
+  familyName: ["e","e","e"],
+  givenName: ["e","e","e"],
+};
+
+var c8 = {
+  name: ["e"],
+  familyName: ["e","e","e"],
+  givenName: ["e","e","e"],
+};
+
+var adr1 = {
+  type: ["work"],
+  streetAddress: "street 1",
+  locality: "locality 1",
+  region: "region 1",
+  postalCode: "postal code 1",
+  countryName: "country 1"
+};
+
+var adr2 = {
+  type: ["home, fax"],
+  streetAddress: "street2",
+  locality: "locality2",
+  region: "region2",
+  postalCode: "postal code2",
+  countryName: "country2"
+};
+
+var properties1 = {
+  // please keep capital letters at the start of these names
+  name: ["Test1 TestFamilyName", "Test2 Wagner"],
+  familyName: ["TestFamilyName","Wagner"],
+  givenName: ["Test1","Test2"],
+  nickname: ["nicktest"],
+  tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
+  adr: [adr1],
+  email: [{type: ["work"], value: "x@y.com"}],
+};
+
+var properties2 = {
+  name: ["dummyHonorificPrefix dummyGivenName dummyFamilyName dummyHonorificSuffix", "dummyHonorificPrefix2"],
+  familyName: ["dummyFamilyName"],
+  givenName: ["dummyGivenName"],
+  honorificPrefix: ["dummyHonorificPrefix","dummyHonorificPrefix2"],
+  honorificSuffix: ["dummyHonorificSuffix"],
+  additionalName: ["dummyadditionalName"],
+  nickname: ["dummyNickname"],
+  tel: [{type: ["test"], value: "7932012345", carrier: "myCarrier", pref: 1},{type: ["home", "custom"], value: "7932012346", pref: 0}],
+  email: [{type: ["test"], value: "a@b.c"}, {value: "b@c.d", pref: 1}],
+  adr: [adr1, adr2],
+  impp: [{type: ["aim"], value:"im1", pref: 1}, {value: "im2"}],
+  org: ["org1", "org2"],
+  jobTitle: ["boss", "superboss"],
+  note: ["test note"],
+  category: ["cat1", "cat2"],
+  url: [{type: ["work", "work2"], value: "www.1.com", pref: 1}, {value:"www2.com"}],
+  bday: new Date("1980, 12, 01"),
+  anniversary: new Date("2000, 12, 01"),
+  sex: "male",
+  genderIdentity: "test",
+  key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
+};
+
+var sample_id1;
+var sample_id2;
+
+var createResult1;
+var createResult2;
+
+var findResult1;
+var findResult2;
+
+// DOMRequest helper functions
+function onUnwantedSuccess() {
+  ok(false, "onUnwantedSuccess: shouldn't get here");
+}
+
+function onFailure() {
+  ok(false, "in on Failure!");
+  next();
+}
+
+// Validation helper functions
+function checkStr(str1, str2, msg) {
+  if (str1 ^ str2) {
+    ok(false, "Expected both strings to be either present or absent");
+    return;
+  }
+  if (!str1 || str1 == "null") {
+    str1 = null;
+  }
+  if (!str2 || str2 == "null") {
+    str2 = null;
+  }
+  is(str1, str2, msg);
+}
+
+function checkStrArray(str1, str2, msg) {
+  function normalize_falsy(v) {
+    if (!v || v == "null" || v == "undefined") {
+      return "";
+    }
+    return v;
+  }
+  function optArray(val) {
+    return Array.isArray(val) ? val : [val];
+  }
+  str1 = optArray(str1).map(normalize_falsy).filter(v => v != "");
+  str2 = optArray(str2).map(normalize_falsy).filter(v => v != "");
+  ise(JSON.stringify(str1), JSON.stringify(str2), msg);
+}
+
+function checkPref(pref1, pref2) {
+  // If on Android treat one preference as 0 and the other as undefined as matching
+  if (isAndroid) {
+    if ((!pref1 && pref2 == undefined) || (pref1 == undefined && !pref2)) {
+      pref1 = false;
+      pref2 = false;
+    }
+  }
+  ise(!!pref1, !!pref2, "Same pref");
+}
+
+function checkAddress(adr1, adr2) {
+  if (adr1 ^ adr2) {
+    ok(false, "Expected both adrs to be either present or absent");
+    return;
+  }
+  checkStrArray(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");
+  checkPref(adr1.pref, adr2.pref);
+}
+
+function checkField(field1, field2) {
+  if (field1 ^ field2) {
+    ok(false, "Expected both fields to be either present or absent");
+    return;
+  }
+  checkStrArray(field1.type, field2.type, "Same type");
+  checkStr(field1.value, field2.value, "Same value");
+  checkPref(field1.pref, field2.pref);
+}
+
+function checkTel(tel1, tel2) {
+  if (tel1 ^ tel2) {
+    ok(false, "Expected both tels to be either present or absent");
+    return;
+  }
+  checkField(tel1, tel2);
+  checkStr(tel1.carrier, tel2.carrier, "Same carrier");
+}
+
+function checkCategory(category1, category2) {
+  // Android adds contacts to the a default category. This should be removed from the
+  // results before comparing them
+  if (isAndroid) {
+    category1 = removeAndroidDefaultCategory(category1);
+    category2 = removeAndroidDefaultCategory(category2);
+  }
+  checkStrArray(category1, category2, "Same Category")
+}
+
+function removeAndroidDefaultCategory(category) {
+  if (!category) {
+    return category;
+  }
+
+  var result = [];
+
+  for (var i of category) {
+    // Some devices may return the full group name (prefixed with "System Group: ")
+    if (i != "My Contacts" && i != "System Group: My Contacts") {
+      result.push(i);
+    }
+  }
+
+  return result;
+}
+
+function checkArrayField(array1, array2, func, msg) {
+  if (!!array1 ^ !!array2) {
+    ok(false, "Expected both arrays to be either present or absent: " + JSON.stringify(array1) + " vs. " + JSON.stringify(array2) + ". (" + msg + ")");
+    return;
+  }
+  if (!array1 && !array2)  {
+    ok(true, msg);
+    return;
+  }
+  ise(array1.length, array2.length, "Same length");
+  for (var i = 0; i < array1.length; ++i) {
+    func(array1[i], array2[i], msg);
+  }
+}
+
+function checkContacts(contact1, contact2) {
+  if (!!contact1 ^ !!contact2) {
+    ok(false, "Expected both contacts to be either present or absent");
+    return;
+  }
+  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");
+  checkCategory(contact1.category, contact2.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");
+  checkStrArray(contact1.note, contact2.note, "Same note");
+  is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
+  checkStr(contact1.sex, contact2.sex, "Same sex");
+  checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
+  checkStrArray(contact1.key, contact2.key, "Same key");
+
+  checkArrayField(contact1.adr, contact2.adr, checkAddress, "Same adr");
+  checkArrayField(contact1.tel, contact2.tel, checkTel, "Same tel");
+  checkArrayField(contact1.email, contact2.email, checkField, "Same email");
+  checkArrayField(contact1.url, contact2.url, checkField, "Same url");
+  checkArrayField(contact1.impp, contact2.impp, checkField, "Same impp");
+}
+
+function addContacts() {
+  ok(true, "Adding 40 contacts");
+  let req;
+  for (let i = 0; i < 39; ++i) {
+    properties1.familyName[0] = "Testname" + (i < 10 ? "0" + i : i);
+    properties1.name = [properties1.givenName[0] + " " + properties1.familyName[0]];
+    createResult1 = new mozContact(properties1);
+    req = mozContacts.save(createResult1);
+    req.onsuccess = function() {
+      ok(createResult1.id, "The contact now has an ID.");
+    };
+    req.onerror = onFailure;
+  };
+  properties1.familyName[0] = "Testname39";
+  properties1.name = [properties1.givenName[0] + " Testname39"];
+  createResult1 = new mozContact(properties1);
+  req = mozContacts.save(createResult1);
+  req.onsuccess = function() {
+    ok(createResult1.id, "The contact now has an ID.");
+    checkStrArray(createResult1.name, properties1.name, "Same Name");
+    next();
+  };
+  req.onerror = onFailure;
+}
+
+function getOne(msg) {
+  return function() {
+    ok(true, msg || "Retrieving one contact with getAll");
+    let req = mozContacts.getAll({});
+
+    let count = 0;
+    req.onsuccess = function(event) {
+      ok(true, "on success");
+      if (req.result) {
+        ok(true, "result is valid");
+        count++;
+        req.continue();
+      } else {
+        is(count, 1, "last contact - only one contact returned");
+        next();
+      }
+    };
+    req.onerror = onFailure;
+  };
+}
+
+function getAll(msg) {
+  return function() {
+    ok(true, msg || "Retrieving 40 contacts with getAll");
+    let 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, 40, "last contact - 40 contacts returned");
+        next();
+      }
+    };
+    req.onerror = onFailure;
+  };
+}
+
+function clearTemps() {
+  sample_id1 = null;
+  sample_id2 = null;
+  createResult1 = null;
+  createResult2 = null;
+  findResult1 = null;
+  findResult2 = null;
+}
+
+function clearDatabase() {
+  ok(true, "Deleting database");
+  let req = mozContacts.clear()
+  req.onsuccess = function () {
+    ok(true, "Deleted the database");
+    next();
+  }
+  req.onerror = onFailure;
+}
+
+function checkCount(count, msg, then) {
+  var request = mozContacts.getCount();
+  request.onsuccess = function(e) {
+    is(e.target.result, count, msg);
+    then();
+  };
+  request.onerror = onFailure;
+}
+
+// Helper functions to run tests
+var index = 0;
+
+function next() {
+  ok(true, "Begin!");
+  if (index >= steps.length) {
+    ok(false, "Shouldn't get here!");
+    return;
+  }
+  try {
+    var i = index++;
+    steps[i]();
+  } catch(ex) {
+    ok(false, "Caught exception", ex);
+  }
+}
+
+function start_tests() {
+  // Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
+  let androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
+                                    .getService(SpecialPowers.Ci.nsIPropertyBag2)
+                                    .getProperty('version');
+  if (!isAndroid || androidVersion >= 14) {
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(next);
+  } else {
+    ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
+  }
+}
--- a/dom/contacts/tests/test_contacts_basics.html
+++ b/dom/contacts/tests/test_contacts_basics.html
@@ -12,341 +12,40 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=674720">Mozilla Bug 674720</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
+<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
 <script class="testbody" type="text/javascript">
-
 "use strict";
 
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
-  SpecialPowers.Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
-}
-
-SpecialPowers.addPermission("contacts-write", true, document);
-SpecialPowers.addPermission("contacts-read", true, document);
-SpecialPowers.addPermission("contacts-create", true, document);
-
-var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
-var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
-                                  .getService(SpecialPowers.Ci.nsIPropertyBag2)
-                                  .getProperty('version');
-
-// For Sorting
-var c1 = {
-  name: ["a a"],
-  familyName: ["a"],
-  givenName: ["a"],
-};
-
-var c2 = {
-  name: ["b b"],
-  familyName: ["b"],
-  givenName: ["b"],
-};
-
-var c3 = {
-  name: ["c c", "a a", "b b"],
-  familyName: ["c","a","b"],
-  givenName: ["c","a","b"],
-};
-
-var c4 = {
-  name: ["c c", "a a", "c c"],
-  familyName: ["c","a","c"],
-  givenName: ["c","a","c"],
-};
-
-var c5 = {
-  familyName: [],
-  givenName: [],
-};
-
-var c6 = {
-  name: ["e"],
-  familyName: ["e","e","e"],
-  givenName: ["e","e","e"],
-};
-
-var c7 = {
-  name: ["e"],
-  familyName: ["e","e","e"],
-  givenName: ["e","e","e"],
-};
-
-var c8 = {
-  name: ["e"],
-  familyName: ["e","e","e"],
-  givenName: ["e","e","e"],
-};
-
-var adr1 = {
-  type: ["work"],
-  streetAddress: "street 1",
-  locality: "locality 1",
-  region: "region 1",
-  postalCode: "postal code 1",
-  countryName: "country 1"
-};
-
-var adr2 = {
-  type: ["home, fax"],
-  streetAddress: "street2",
-  locality: "locality2",
-  region: "region2",
-  postalCode: "postal code2",
-  countryName: "country2"
-};
-
-var properties1 = {
-  // please keep capital letters at the start of these names
-  name: ["Test1 TestFamilyName", "Test2 Wagner"],
-  familyName: ["TestFamilyName","Wagner"],
-  givenName: ["Test1","Test2"],
-  nickname: ["nicktest"],
-  tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
-  adr: [adr1],
-  email: [{type: ["work"], value: "x@y.com"}],
-};
-
-var properties2 = {
-  name: ["dummyHonorificPrefix dummyGivenName dummyFamilyName dummyHonorificSuffix", "dummyHonorificPrefix2"],
-  familyName: ["dummyFamilyName"],
-  givenName: ["dummyGivenName"],
-  honorificPrefix: ["dummyHonorificPrefix","dummyHonorificPrefix2"],
-  honorificSuffix: ["dummyHonorificSuffix"],
-  additionalName: ["dummyadditionalName"],
-  nickname: ["dummyNickname"],
-  tel: [{type: ["test"], value: "7932012345", carrier: "myCarrier", pref: 1},{type: ["home", "custom"], value: "7932012346", pref: 0}],
-  email: [{type: ["test"], value: "a@b.c"}, {value: "b@c.d", pref: 1}],
-  adr: [adr1, adr2],
-  impp: [{type: ["aim"], value:"im1", pref: 1}, {value: "im2"}],
-  org: ["org1", "org2"],
-  jobTitle: ["boss", "superboss"],
-  note: ["test note"],
-  category: ["cat1", "cat2"],
-  url: [{type: ["work", "work2"], value: "www.1.com", pref: 1}, {value:"www2.com"}],
-  bday: new Date("1980, 12, 01"),
-  anniversary: new Date("2000, 12, 01"),
-  sex: "male",
-  genderIdentity: "test",
-  key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
-};
-
-var sample_id1;
-var sample_id2;
-
-var createResult1;
-var createResult2;
-
-var findResult1;
-var findResult2;
-
-function clearTemps() {
-  sample_id1 = null;
-  sample_id2 = null;
-  createResult1 = null;
-  createResult2 = null;
-  findResult1 = null;
-  findResult2 = null;
-}
-
-function onUnwantedSuccess() {
-  ok(false, "onUnwantedSuccess: shouldn't get here");
-}
-
-function onFailure() {
-  ok(false, "in on Failure!");
-  next();
-}
-
-function checkStr(str1, str2, msg) {
-  if (str1 ^ str2) {
-    ok(false, "Expected both strings to be either present or absent");
-    return;
-  }
-  if (!str1 || str1 == "null") {
-    str1 = null;
-  }
-  if (!str2 || str2 == "null") {
-    str2 = null;
-  }
-  is(str1, str2, msg);
-}
-
-function checkStrArray(str1, str2, msg) {
-  function normalize_falsy(v) {
-    if (!v || v == "null" || v == "undefined") {
-      return "";
-    }
-    return v;
-  }
-  function optArray(val) {
-    return Array.isArray(val) ? val : [val];
-  }
-  str1 = optArray(str1).map(normalize_falsy).filter(v => v != "");
-  str2 = optArray(str2).map(normalize_falsy).filter(v => v != "");
-  ise(JSON.stringify(str1), JSON.stringify(str2), msg);
-}
-
-function checkPref(pref1, pref2) {
-  // If on Android treat one preference as 0 and the other as undefined as matching
-  if (isAndroid) {
-    if ((!pref1 && pref2 == undefined) || (pref1 == undefined && !pref2)) {
-      pref1 = false;
-      pref2 = false;
-    }
-  }
-  ise(!!pref1, !!pref2, "Same pref");
-}
-
-function checkAddress(adr1, adr2) {
-  if (adr1 ^ adr2) {
-    ok(false, "Expected both adrs to be either present or absent");
-    return;
-  }
-  checkStrArray(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");
-  checkPref(adr1.pref, adr2.pref);
-}
-
-function checkField(field1, field2) {
-  if (field1 ^ field2) {
-    ok(false, "Expected both fields to be either present or absent");
-    return;
-  }
-  checkStrArray(field1.type, field2.type, "Same type");
-  checkStr(field1.value, field2.value, "Same value");
-  checkPref(field1.pref, field2.pref);
-}
-
-function checkTel(tel1, tel2) {
-  if (tel1 ^ tel2) {
-    ok(false, "Expected both tels to be either present or absent");
-    return;
-  }
-  checkField(tel1, tel2);
-  checkStr(tel1.carrier, tel2.carrier, "Same carrier");
-}
-
-function checkCategory(category1, category2) {
-  // Android adds contacts to the a default category. This should be removed from the
-  // results before comparing them
-  if (isAndroid) {
-    category1 = removeAndroidDefaultCategory(category1);
-    category2 = removeAndroidDefaultCategory(category2);
-  }
-  checkStrArray(category1, category2, "Same Category")
-}
-
-function removeAndroidDefaultCategory(category) {
-  if (!category) {
-    return category;
-  }
-
-  var result = [];
-
-  for (var i of category) {
-    // Some devices may return the full group name (prefixed with "System Group: ")
-    if (i != "My Contacts" && i != "System Group: My Contacts") {
-      result.push(i);
-    }
-  }
-
-  return result;
-}
-
-function checkArrayField(array1, array2, func, msg) {
-  if (!!array1 ^ !!array2) {
-    ok(false, "Expected both arrays to be either present or absent: " + JSON.stringify(array1) + " vs. " + JSON.stringify(array2) + ". (" + msg + ")");
-    return;
-  }
-  if (!array1 && !array2)  {
-    ok(true, msg);
-    return;
-  }
-  ise(array1.length, array2.length, "Same length");
-  for (var i = 0; i < array1.length; ++i) {
-    func(array1[i], array2[i], msg);
-  }
-}
-
-function checkContacts(contact1, contact2) {
-  if (!!contact1 ^ !!contact2) {
-    ok(false, "Expected both contacts to be either present or absent");
-    return;
-  }
-  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");
-  checkCategory(contact1.category, contact2.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");
-  checkStrArray(contact1.note, contact2.note, "Same note");
-  is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
-  checkStr(contact1.sex, contact2.sex, "Same sex");
-  checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
-  checkStrArray(contact1.key, contact2.key, "Same key");
-
-  checkArrayField(contact1.adr, contact2.adr, checkAddress, "Same adr");
-  checkArrayField(contact1.tel, contact2.tel, checkTel, "Same tel");
-  checkArrayField(contact1.email, contact2.email, checkField, "Same email");
-  checkArrayField(contact1.url, contact2.url, checkField, "Same url");
-  checkArrayField(contact1.impp, contact2.impp, checkField, "Same impp");
-}
-
-var req;
-var index = 0;
-
 var initialRev;
 
-var defaultOptions = {
-  sortBy: "givenName",
-};
-
 function checkRevision(revision, msg, then) {
   var revReq = mozContacts.getRevision();
   revReq.onsuccess = function(e) {
     is(e.target.result, initialRev+revision, msg);
     then();
   };
   // The revision function isn't supported on Android so treat on failure as success
   if (isAndroid) {
     revReq.onerror = function(e) {
       then();
     };
   } else {
     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 req;
 
-var mozContacts = window.navigator.mozContacts;
 var steps = [
   function() {
     req = mozContacts.getRevision();
     req.onsuccess = function(e) {
       initialRev = e.target.result;
       next();
     };
 
@@ -1063,34 +762,13 @@ var steps = [
   function () {
     ok(true, "all done!\n");
     clearTemps();
 
     SimpleTest.finish();
   }
 ];
 
-function next() {
-  ok(true, "Begin!");
-  if (index >= steps.length) {
-    ok(false, "Shouldn't get here!");
-    return;
-  }
-  try {
-    var i = index++;
-    steps[i]();
-  } catch(ex) {
-    ok(false, "Caught exception", ex);
-  }
-}
-
-// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
-if (!isAndroid || androidVersion >= 14) {
-  SimpleTest.waitForExplicitFinish();
-  addLoadEvent(next);
-} else {
-  ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
-}
-
+start_tests();
 </script>
 </pre>
 </body>
 </html>
--- a/dom/contacts/tests/test_contacts_basics2.html
+++ b/dom/contacts/tests/test_contacts_basics2.html
@@ -12,341 +12,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=674720">Mozilla Bug 674720</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
+<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
 <script class="testbody" type="text/javascript">
-
 "use strict";
 
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
-  SpecialPowers.Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
-}
-
-SpecialPowers.addPermission("contacts-write", true, document);
-SpecialPowers.addPermission("contacts-read", true, document);
-SpecialPowers.addPermission("contacts-create", true, document);
-
-var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
-var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
-                                  .getService(SpecialPowers.Ci.nsIPropertyBag2)
-                                  .getProperty('version');
-
-// For Sorting
-var c1 = {
-  name: ["a a"],
-  familyName: ["a"],
-  givenName: ["a"],
-};
-
-var c2 = {
-  name: ["b b"],
-  familyName: ["b"],
-  givenName: ["b"],
-};
-
-var c3 = {
-  name: ["c c", "a a", "b b"],
-  familyName: ["c","a","b"],
-  givenName: ["c","a","b"],
-};
-
-var c4 = {
-  name: ["c c", "a a", "c c"],
-  familyName: ["c","a","c"],
-  givenName: ["c","a","c"],
-};
-
-var c5 = {
-  familyName: [],
-  givenName: [],
-};
-
-var c6 = {
-  name: ["e"],
-  familyName: ["e","e","e"],
-  givenName: ["e","e","e"],
-};
-
-var c7 = {
-  name: ["e"],
-  familyName: ["e","e","e"],
-  givenName: ["e","e","e"],
-};
-
-var c8 = {
-  name: ["e"],
-  familyName: ["e","e","e"],
-  givenName: ["e","e","e"],
-};
-
-var adr1 = {
-  type: ["work"],
-  streetAddress: "street 1",
-  locality: "locality 1",
-  region: "region 1",
-  postalCode: "postal code 1",
-  countryName: "country 1"
-};
-
-var adr2 = {
-  type: ["home, fax"],
-  streetAddress: "street2",
-  locality: "locality2",
-  region: "region2",
-  postalCode: "postal code2",
-  countryName: "country2"
-};
-
-var properties1 = {
-  // please keep capital letters at the start of these names
-  name: ["Test1 TestFamilyName", "Test2 Wagner"],
-  familyName: ["TestFamilyName","Wagner"],
-  givenName: ["Test1","Test2"],
-  nickname: ["nicktest"],
-  tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
-  adr: [adr1],
-  email: [{type: ["work"], value: "x@y.com"}],
-};
-
-var properties2 = {
-  name: ["dummyHonorificPrefix dummyGivenName dummyFamilyName dummyHonorificSuffix", "dummyHonorificPrefix2"],
-  familyName: ["dummyFamilyName"],
-  givenName: ["dummyGivenName"],
-  honorificPrefix: ["dummyHonorificPrefix","dummyHonorificPrefix2"],
-  honorificSuffix: ["dummyHonorificSuffix"],
-  additionalName: ["dummyadditionalName"],
-  nickname: ["dummyNickname"],
-  tel: [{type: ["test"], value: "7932012345", carrier: "myCarrier", pref: 1},{type: ["home", "custom"], value: "7932012346", pref: 0}],
-  email: [{type: ["test"], value: "a@b.c"}, {value: "b@c.d", pref: 1}],
-  adr: [adr1, adr2],
-  impp: [{type: ["aim"], value:"im1", pref: 1}, {value: "im2"}],
-  org: ["org1", "org2"],
-  jobTitle: ["boss", "superboss"],
-  note: ["test note"],
-  category: ["cat1", "cat2"],
-  url: [{type: ["work", "work2"], value: "www.1.com", pref: 1}, {value:"www2.com"}],
-  bday: new Date("1980, 12, 01"),
-  anniversary: new Date("2000, 12, 01"),
-  sex: "male",
-  genderIdentity: "test",
-  key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
-};
-
-var sample_id1;
-var sample_id2;
-
-var createResult1;
-var createResult2;
-
-var findResult1;
-var findResult2;
-
-function clearTemps() {
-  sample_id1 = null;
-  sample_id2 = null;
-  createResult1 = null;
-  createResult2 = null;
-  findResult1 = null;
-  findResult2 = null;
-}
-
-function onUnwantedSuccess() {
-  ok(false, "onUnwantedSuccess: shouldn't get here");
-}
-
-function onFailure() {
-  ok(false, "in on Failure!");
-  next();
-}
-
-function checkStr(str1, str2, msg) {
-  if (str1 ^ str2) {
-    ok(false, "Expected both strings to be either present or absent");
-    return;
-  }
-  if (!str1 || str1 == "null") {
-    str1 = null;
-  }
-  if (!str2 || str2 == "null") {
-    str2 = null;
-  }
-  is(str1, str2, msg);
-}
+var req;
 
-function checkStrArray(str1, str2, msg) {
-  function normalize_falsy(v) {
-    if (!v || v == "null" || v == "undefined") {
-      return "";
-    }
-    return v;
-  }
-  function optArray(val) {
-    return Array.isArray(val) ? val : [val];
-  }
-  str1 = optArray(str1).map(normalize_falsy).filter(v => v != "");
-  str2 = optArray(str2).map(normalize_falsy).filter(v => v != "");
-  ise(JSON.stringify(str1), JSON.stringify(str2), msg);
-}
-
-function checkPref(pref1, pref2) {
-  // If on Android treat one preference as 0 and the other as undefined as matching
-  if (isAndroid) {
-    if ((!pref1 && pref2 == undefined) || (pref1 == undefined && !pref2)) {
-      pref1 = false;
-      pref2 = false;
-    }
-  }
-  ise(!!pref1, !!pref2, "Same pref");
-}
-
-function checkAddress(adr1, adr2) {
-  if (adr1 ^ adr2) {
-    ok(false, "Expected both adrs to be either present or absent");
-    return;
-  }
-  checkStrArray(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");
-  checkPref(adr1.pref, adr2.pref);
-}
-
-function checkField(field1, field2) {
-  if (field1 ^ field2) {
-    ok(false, "Expected both fields to be either present or absent");
-    return;
-  }
-  checkStrArray(field1.type, field2.type, "Same type");
-  checkStr(field1.value, field2.value, "Same value");
-  checkPref(field1.pref, field2.pref);
-}
-
-function checkTel(tel1, tel2) {
-  if (tel1 ^ tel2) {
-    ok(false, "Expected both tels to be either present or absent");
-    return;
-  }
-  checkField(tel1, tel2);
-  checkStr(tel1.carrier, tel2.carrier, "Same carrier");
-}
-
-function checkCategory(category1, category2) {
-  // Android adds contacts to the a default category. This should be removed from the
-  // results before comparing them
-  if (isAndroid) {
-    category1 = removeAndroidDefaultCategory(category1);
-    category2 = removeAndroidDefaultCategory(category2);
-  }
-  checkStrArray(category1, category2, "Same Category")
-}
-
-function removeAndroidDefaultCategory(category) {
-  if (!category) {
-    return category;
-  }
-
-  var result = [];
-
-  for (var i of category) {
-    // Some devices may return the full group name (prefixed with "System Group: ")
-    if (i != "My Contacts" && i != "System Group: My Contacts") {
-      result.push(i);
-    }
-  }
-
-  return result;
-}
-
-function checkArrayField(array1, array2, func, msg) {
-  if (!!array1 ^ !!array2) {
-    ok(false, "Expected both arrays to be either present or absent: " + JSON.stringify(array1) + " vs. " + JSON.stringify(array2) + ". (" + msg + ")");
-    return;
-  }
-  if (!array1 && !array2)  {
-    ok(true, msg);
-    return;
-  }
-  ise(array1.length, array2.length, "Same length");
-  for (var i = 0; i < array1.length; ++i) {
-    func(array1[i], array2[i], msg);
-  }
-}
-
-function checkContacts(contact1, contact2) {
-  if (!!contact1 ^ !!contact2) {
-    ok(false, "Expected both contacts to be either present or absent");
-    return;
-  }
-  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");
-  checkCategory(contact1.category, contact2.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");
-  checkStrArray(contact1.note, contact2.note, "Same note");
-  is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
-  checkStr(contact1.sex, contact2.sex, "Same sex");
-  checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
-  checkStrArray(contact1.key, contact2.key, "Same key");
-
-  checkArrayField(contact1.adr, contact2.adr, checkAddress, "Same adr");
-  checkArrayField(contact1.tel, contact2.tel, checkTel, "Same tel");
-  checkArrayField(contact1.email, contact2.email, checkField, "Same email");
-  checkArrayField(contact1.url, contact2.url, checkField, "Same url");
-  checkArrayField(contact1.impp, contact2.impp, checkField, "Same impp");
-}
-
-var req;
-var index = 0;
-
-var initialRev;
-
-var defaultOptions = {
-  sortBy: "givenName",
-};
-
-function checkRevision(revision, msg, then) {
-  var revReq = mozContacts.getRevision();
-  revReq.onsuccess = function(e) {
-    is(e.target.result, initialRev+revision, msg);
-    then();
-  };
-  // The revision function isn't supported on Android so treat on failure as success
-  if (isAndroid) {
-    revReq.onerror = function(e) {
-      then();
-    };
-  } else {
-    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;
 var steps = [
   function () {
     ok(true, "Adding a new contact");
     createResult1 = new mozContact(properties1);
     req = mozContacts.save(createResult1)
     req.onsuccess = function () {
       ok(createResult1.id, "The contact now has an ID.");
       sample_id1 = createResult1.id;
@@ -434,17 +115,16 @@ var steps = [
       next();
     }
     req.onerror = onFailure;
   },
   function () {
     ok(true, "Deleting database");
     req = mozContacts.clear();
     req.onsuccess = function () {
-      clearTemps();
       next();
     }
     req.onerror = onFailure;
   },
   function () {
     ok(true, "Adding 20 contacts");
     for (var i=0; i<19; i++) {
       createResult1 = new mozContact(properties1);
@@ -519,17 +199,16 @@ var steps = [
       next();
     }
     req.onerror = onFailure;
   },
   function () {
     ok(true, "Deleting database");
     req = mozContacts.clear();
     req.onsuccess = function () {
-      clearTemps();
       next();
     }
     req.onerror = onFailure;
   },
   function () {
     ok(true, "Testing clone contact");
     createResult1 = new mozContact(properties1);
     req = mozContacts.save(createResult1);
@@ -1039,18 +718,16 @@ var steps = [
     testArrayProp("adr");
     testArrayProp("tel");
     testArrayProp("impp");
     testArrayProp("url");
     next();
   },
   function () {
     ok(true, "all done!\n");
-    clearTemps();
-
     SimpleTest.finish();
   }
 ];
 
 function next() {
   ok(true, "Begin!");
   if (index >= steps.length) {
     ok(false, "Shouldn't get here!");
@@ -1059,20 +736,13 @@ function next() {
   try {
     var i = index++;
     steps[i]();
   } catch(ex) {
     ok(false, "Caught exception", ex);
   }
 }
 
-// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
-if (!isAndroid || androidVersion >= 14) {
-  SimpleTest.waitForExplicitFinish();
-  addLoadEvent(next);
-} else {
-  ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
-}
-
+start_tests();
 </script>
 </pre>
 </body>
 </html>
--- a/dom/contacts/tests/test_contacts_blobs.html
+++ b/dom/contacts/tests/test_contacts_blobs.html
@@ -12,34 +12,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=674720">Mozilla Bug 674720</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
+<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
 <script class="testbody" type="text/javascript">
-
 "use strict";
 
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
-  SpecialPowers.Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
-}
-
-SpecialPowers.addPermission("contacts-write", true, document);
-SpecialPowers.addPermission("contacts-read", true, document);
-SpecialPowers.addPermission("contacts-create", true, document);
-
-var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
-var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
-                                  .getService(SpecialPowers.Ci.nsIPropertyBag2)
-                                  .getProperty('version');
-
 var utils = SpecialPowers.getDOMWindowUtils(window);
 
 function getView(size)
 {
  var buffer = new ArrayBuffer(size);
  var view = new Uint8Array(buffer);
  is(buffer.byteLength, size, "Correct byte length");
  return view;
@@ -100,25 +86,16 @@ var properties2 = {
   givenName: ["yTestname2"],
   photo: [randomBlob, randomBlob2]
 };
 
 var sample_id1;
 var createResult1;
 var findResult1;
 
-function onUnwantedSuccess() {
-  ok(false, "onUnwantedSuccess: shouldn't get here");
-}
-
-function onFailure() {
-  ok(false, "in on Failure!");
-  next();
-}
-
 function verifyBlob(blob1, blob2, isLast)
 {
   is(blob1 instanceof SpecialPowers.Ci.nsIDOMBlob, true,
      "Instance of nsIDOMBlob");
   is(blob1 instanceof SpecialPowers.Ci.nsIDOMFile,
      blob2 instanceof SpecialPowers.Ci.nsIDOMFile,
      "Instance of nsIDOMFile");
   is(blob1.size, blob2.size, "Correct size");
@@ -156,19 +133,16 @@ function verifyBlobArray(blobs1, blobs2)
     return;
   }
 
   for (var i = 0; i < blobs1.length; i++)
     verifyBlob(blobs1[i], blobs2[i], i == blobs1.length - 1);
 }
 
 var req;
-var index = 0;
-
-var mozContacts = window.navigator.mozContacts
 
 var steps = [
   function () {
     ok(true, "Deleting database");
     req = mozContacts.clear();
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
@@ -236,34 +210,13 @@ var steps = [
   },
   function () {
     ok(true, "all done!\n");
 
     SimpleTest.finish();
   }
 ];
 
-function next() {
-  ok(true, "Begin!");
-  if (index >= steps.length) {
-    ok(false, "Shouldn't get here!");
-    return;
-  }
-  try {
-    steps[index]();
-  } catch(ex) {
-    ok(false, "Caught exception", ex);
-  }
-  index += 1;
-}
-
-// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
-if (!isAndroid || androidVersion >= 14) {
-  SimpleTest.waitForExplicitFinish();
-  addLoadEvent(next);
-} else {
-  ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
-}
-
+start_tests();
 </script>
 </pre>
 </body>
 </html>
--- a/dom/contacts/tests/test_contacts_getall.html
+++ b/dom/contacts/tests/test_contacts_getall.html
@@ -12,277 +12,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=836519">Mozilla Bug 836519</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
-<script class="testbody" type="text/javascript;version=1.7">
-
+<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
+<script class="testbody" type="text/javascript;version=1.8">
 "use strict";
 
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
-  SpecialPowers.Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
-}
-
-SpecialPowers.addPermission("contacts-write", true, document);
-SpecialPowers.addPermission("contacts-read", true, document);
-SpecialPowers.addPermission("contacts-create", true, document);
-
-var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
-var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
-                                  .getService(SpecialPowers.Ci.nsIPropertyBag2)
-                                  .getProperty('version');
-
-let adr1 = {
-  type: ["work"],
-  streetAddress: "street 1",
-  locality: "locality 1",
-  region: "region 1",
-  postalCode: "postal code 1",
-  countryName: "country 1"
-};
-
-let properties1 = {
-  name: ["Testname1 TestFamilyName"],
-  familyName: ["TestFamilyName","Wagner"],
-  givenName: ["Test1","Test2"],
-  nickname: ["nicktest"],
-  tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+9-876-5432"}],
-  adr: [adr1],
-  email: [{type: ["work"], value: "x@y.com"}]
-};
-
-function onFailure() {
-  ok(false, "in on Failure!");
-  next();
-}
-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) {
-  function normalize_falsy(k, v) {
-    if (!v || v == "null" || v == "undefined") {
-      return "";
-    }
-    return v;
-  }
-  ise(JSON.stringify(str1, normalize_falsy), JSON.stringify(str2, normalize_falsy), msg);
-}
-
-function checkPref(pref1, pref2) {
-  // If on Android treat one preference as 0 and the other as undefined as matching
-  if (isAndroid) {
-    if ((!pref1 && pref2 == undefined) || (pref1 == undefined && !pref2)) {
-      pref1 = false;
-      pref2 = false;
-    }
-  }
-  ise(!!pref1, !!pref2, "Same pref");
-}
-
-function checkAddress(adr1, adr2) {
-  if (adr1 ^ adr2) {
-    ok(false, "Expected both adrs to be either present or absent");
-    return;
-  }
-  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");
-  checkPref(adr1.pref, adr2.pref);
-}
-
-function checkField(field1, field2) {
-  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");
-  checkPref(field1.pref, field2.pref);
-}
-
-function checkTel(tel1, tel2) {
-  if (tel1 ^ tel2) {
-    ok(false, "Expected both tels to be either present or absent");
-    return;
-  }
-  checkField(tel1, tel2);
-  checkStrArray(tel1.carrier, tel2.carrier, "Same carrier");
-}
-
-function checkCategory(category1, category2) {
-  // Android adds contacts to the a default category. This should be removed from the
-  // results before comparing them
-  if (isAndroid) {
-    category1 = removeAndroidDefaultCategory(category1);
-    category2 = removeAndroidDefaultCategory(category2);
-  }
-  checkStrArray(category1, category2, "Same Category")
-}
-
-function removeAndroidDefaultCategory(category) {
-  if (!category) {
-    return category;
-  }
-
-  var result = [];
-
-  for (var i of category) {
-    // Some devices may return the full group name (prefixed with "System Group: ")
-    if (i != "My Contacts" && i != "System Group: My Contacts") {
-      result.push(i);
-    }
-  }
-
-  return result;
-}
-
-function checkArrayField(array1, array2, func, msg) {
-  if (!!array1 ^ !!array2) {
-    ok(false, "Expected both arrays to be either present or absent");
-    return;
-  }
-  if (!array1 && !array2)  {
-    ok(true, msg);
-    return;
-  }
-  ise(array1.length, array2.length, "Same length");
-  for (var i = 0; i < array1.length; ++i) {
-    func(array1[i], array2[i], msg);
-  }
-}
-
-function checkContacts(contact1, contact2) {
-  if (!!contact1 ^ !!contact2) {
-    ok(false, "Expected both contacts to be either present or absent");
-    return;
-  }
-  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");
-  checkCategory(contact1.category, contact2.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");
-  checkStrArray(contact1.note, contact2.note, "Same note");
-  is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
-  checkStr(contact1.sex, contact2.sex, "Same sex");
-  checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
-  checkStrArray(contact1.key, contact2.key, "Same key");
-
-  checkArrayField(contact1.adr, contact2.adr, checkAddress, "Same adr");
-  checkArrayField(contact1.tel, contact2.tel, checkTel, "Same tel");
-  checkArrayField(contact1.email, contact2.email, checkField, "Same email");
-  checkArrayField(contact1.url, contact2.url, checkField, "Same url");
-  checkArrayField(contact1.impp, contact2.impp, checkField, "Same impp");
-}
-
-function clearDatabase() {
-  ok(true, "Clearing database");
-  req = mozContacts.clear();
-  req.onsuccess = function() {
-    ok(true, "Cleared the database");
-    next();
-  };
-  req.onerror = onFailure;
-}
-
-function addContacts() {
-  ok(true, "Adding 40 contacts");
-  for (let i = 0; i < 39; ++i) {
-    properties1.familyName[0] = "Testname" + (i < 10 ? "0" + i : i);
-    properties1.name = [properties1.givenName[0] + " " + properties1.familyName[0]];
-    createResult1 = new mozContact(properties1);
-    req = mozContacts.save(createResult1);
-    req.onsuccess = function() {
-      ok(createResult1.id, "The contact now has an ID.");
-    };
-    req.onerror = onFailure;
-  };
-  properties1.familyName[0] = "Testname39";
-  properties1.name = [properties1.givenName[0] + " Testname39"];
-  createResult1 = new mozContact(properties1);
-  req = mozContacts.save(createResult1);
-  req.onsuccess = function() {
-    ok(createResult1.id, "The contact now has an ID.");
-    checkStrArray(createResult1.name, properties1.name, "Same Name");
-    next();
-  };
-  req.onerror = onFailure;
-}
-
-let createResult1;
-
-let index = 0;
 let req;
-let mozContacts = window.navigator.mozContacts;
-
-function getOne(msg) {
-  return function() {
-    ok(true, msg || "Retrieving one contact with getAll");
-    req = mozContacts.getAll({});
-
-    let count = 0;
-    req.onsuccess = function(event) {
-      ok(true, "on success");
-      if (req.result) {
-        ok(true, "result is valid");
-        count++;
-        req.continue();
-      } else {
-        is(count, 1, "last contact - only one contact returned");
-        next();
-      }
-    };
-    req.onerror = onFailure;
-  };
-}
-
-function getAll(msg) {
-  return function() {
-    ok(true, msg || "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, 40, "last contact - 40 contacts returned");
-        next();
-      }
-    };
-    req.onerror = onFailure;
-  }
-}
 
 let steps = [
   function start() {
     SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_START");
     next();
   },
   clearDatabase,
   addContacts,
@@ -396,34 +140,13 @@ let steps = [
 
   function() {
     ok(true, "all done!\n");
     SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_END");
     SimpleTest.finish();
   }
 ];
 
-function next() {
-  ok(true, "Begin!");
-  if (index >= steps.length) {
-    ok(false, "Shouldn't get here!");
-    return;
-  }
-  let i = index++;
-  try {
-    steps[i]();
-  } catch(ex) {
-    ok(false, "Caught exception", ex);
-  }
-}
-
-// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
-if (!isAndroid || androidVersion >= 14) {
-  SimpleTest.waitForExplicitFinish();
-  addLoadEvent(next);
-} else {
-  ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
-}
-
+start_tests();
 </script>
 </pre>
 </body>
 </html>
--- a/dom/contacts/tests/test_contacts_getall2.html
+++ b/dom/contacts/tests/test_contacts_getall2.html
@@ -12,283 +12,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=836519">Mozilla Bug 836519</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
-<script class="testbody" type="text/javascript;version=1.7">
-
+<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
+<script class="testbody" type="text/javascript;version=1.8">
 "use strict";
-
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
-  SpecialPowers.Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
-}
-
-SpecialPowers.addPermission("contacts-write", true, document);
-SpecialPowers.addPermission("contacts-read", true, document);
-SpecialPowers.addPermission("contacts-create", true, document);
-
-var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
-var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
-                                  .getService(SpecialPowers.Ci.nsIPropertyBag2)
-                                  .getProperty('version');
-
-let adr1 = {
-  type: ["work"],
-  streetAddress: "street 1",
-  locality: "locality 1",
-  region: "region 1",
-  postalCode: "postal code 1",
-  countryName: "country 1"
-};
-
-let properties1 = {
-  name: ["Testname1 TestFamilyName"],
-  familyName: ["TestFamilyName","Wagner"],
-  givenName: ["Test1","Test2"],
-  nickname: ["nicktest"],
-  tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+9-876-5432"}],
-  adr: [adr1],
-  email: [{type: ["work"], value: "x@y.com"}]
-};
-
-function onFailure() {
-  ok(false, "in on Failure!");
-  next();
-}
-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) {
-  function normalize_falsy(k, v) {
-    if (!v || v == "null" || v == "undefined") {
-      return "";
-    }
-    return v;
-  }
-  ise(JSON.stringify(str1, normalize_falsy), JSON.stringify(str2, normalize_falsy), msg);
-}
-
-function checkPref(pref1, pref2) {
-  // If on Android treat one preference as 0 and the other as undefined as matching
-  if (isAndroid) {
-    if ((!pref1 && pref2 == undefined) || (pref1 == undefined && !pref2)) {
-      pref1 = false;
-      pref2 = false;
-    }
-  }
-  ise(!!pref1, !!pref2, "Same pref");
-}
-
-function checkAddress(adr1, adr2) {
-  if (adr1 ^ adr2) {
-    ok(false, "Expected both adrs to be either present or absent");
-    return;
-  }
-  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");
-  checkPref(adr1.pref, adr2.pref);
-}
-
-function checkField(field1, field2) {
-  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");
-  checkPref(field1.pref, field2.pref);
-}
-
-function checkTel(tel1, tel2) {
-  if (tel1 ^ tel2) {
-    ok(false, "Expected both tels to be either present or absent");
-    return;
-  }
-  checkField(tel1, tel2);
-  checkStrArray(tel1.carrier, tel2.carrier, "Same carrier");
-}
-
-function checkCategory(category1, category2) {
-  // Android adds contacts to the a default category. This should be removed from the
-  // results before comparing them
-  if (isAndroid) {
-    category1 = removeAndroidDefaultCategory(category1);
-    category2 = removeAndroidDefaultCategory(category2);
-  }
-  checkStrArray(category1, category2, "Same Category")
-}
-
-function removeAndroidDefaultCategory(category) {
-  if (!category) {
-    return category;
-  }
-
-  var result = [];
-
-  for (var i of category) {
-    // Some devices may return the full group name (prefixed with "System Group: ")
-    if (i != "My Contacts" && i != "System Group: My Contacts") {
-      result.push(i);
-    }
-  }
-
-  return result;
-}
-
-function checkArrayField(array1, array2, func, msg) {
-  if (!!array1 ^ !!array2) {
-    ok(false, "Expected both arrays to be either present or absent");
-    return;
-  }
-  if (!array1 && !array2)  {
-    ok(true, msg);
-    return;
-  }
-  ise(array1.length, array2.length, "Same length");
-  for (var i = 0; i < array1.length; ++i) {
-    func(array1[i], array2[i], msg);
-  }
-}
-
-function checkContacts(contact1, contact2) {
-  if (!!contact1 ^ !!contact2) {
-    ok(false, "Expected both contacts to be either present or absent");
-    return;
-  }
-  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");
-  checkCategory(contact1.category, contact2.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");
-  checkStrArray(contact1.note, contact2.note, "Same note");
-  is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
-  checkStr(contact1.sex, contact2.sex, "Same sex");
-  checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
-  checkStrArray(contact1.key, contact2.key, "Same key");
-
-  checkArrayField(contact1.adr, contact2.adr, checkAddress, "Same adr");
-  checkArrayField(contact1.tel, contact2.tel, checkTel, "Same tel");
-  checkArrayField(contact1.email, contact2.email, checkField, "Same email");
-  checkArrayField(contact1.url, contact2.url, checkField, "Same url");
-  checkArrayField(contact1.impp, contact2.impp, checkField, "Same impp");
-}
-
-function clearDatabase() {
-  ok(true, "Clearing database");
-  req = mozContacts.clear();
-  req.onsuccess = function() {
-    ok(true, "Cleared the database");
-    next();
-  };
-  req.onerror = onFailure;
-}
-
-function addContacts() {
-  ok(true, "Adding 40 contacts");
-  for (let i = 0; i < 39; ++i) {
-    properties1.familyName[0] = "Testname" + (i < 10 ? "0" + i : i);
-    properties1.name = [properties1.givenName[0] + " " + properties1.familyName[0]];
-    createResult1 = new mozContact(properties1);
-    req = mozContacts.save(createResult1);
-    req.onsuccess = function() {
-      ok(createResult1.id, "The contact now has an ID.");
-    };
-    req.onerror = onFailure;
-  };
-  properties1.familyName[0] = "Testname39";
-  properties1.name = [properties1.givenName[0] + " Testname39"];
-  createResult1 = new mozContact(properties1);
-  req = mozContacts.save(createResult1);
-  req.onsuccess = function() {
-    ok(createResult1.id, "The contact now has an ID.");
-    checkStrArray(createResult1.name, properties1.name, "Same Name");
-    next();
-  };
-  req.onerror = onFailure;
-}
-
-let createResult1;
-
-let index = 0;
 let req;
-let mozContacts = window.navigator.mozContacts;
-
-function getOne(msg) {
-  return function() {
-    ok(true, msg || "Retrieving one contact with getAll");
-    req = mozContacts.getAll({});
-
-    let count = 0;
-    req.onsuccess = function(event) {
-      ok(true, "on success");
-      if (req.result) {
-        ok(true, "result is valid");
-        count++;
-        req.continue();
-      } else {
-        is(count, 1, "last contact - only one contact returned");
-        next();
-      }
-    };
-    req.onerror = onFailure;
-  };
-}
-
-function getAll(msg) {
-  return function() {
-    ok(true, msg || "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, 40, "last contact - 40 contacts returned");
-        next();
-      }
-    };
-    req.onerror = onFailure;
-  }
-}
 
 let steps = [
-  function start() {
-    SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_START");
-    next();
-  },
   clearDatabase,
   function() {
     // add a contact
     createResult1 = new mozContact({});
     req = navigator.mozContacts.save(createResult1);
     req.onsuccess = function() {
       next();
     };
@@ -365,39 +104,17 @@ let steps = [
       };
     };
   },
 
   clearDatabase,
 
   function() {
     ok(true, "all done!\n");
-    SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_END");
     SimpleTest.finish();
   }
 ];
 
-function next() {
-  ok(true, "Begin!");
-  if (index >= steps.length) {
-    ok(false, "Shouldn't get here!");
-    return;
-  }
-  let i = index++;
-  try {
-    steps[i]();
-  } catch(ex) {
-    ok(false, "Caught exception", ex);
-  }
-}
-
-// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
-if (!isAndroid || androidVersion >= 14) {
-  SimpleTest.waitForExplicitFinish();
-  addLoadEvent(next);
-} else {
-  ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
-}
-
+start_tests();
 </script>
 </pre>
 </body>
 </html>
--- a/dom/contacts/tests/test_contacts_international.html
+++ b/dom/contacts/tests/test_contacts_international.html
@@ -12,39 +12,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815833">Mozilla Bug 815833</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
+<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
 <script class="testbody" type="text/javascript">
-
 "use strict";
 
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
-  SpecialPowers.Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
-}
-
-SpecialPowers.addPermission("contacts-write", true, document);
-SpecialPowers.addPermission("contacts-read", true, document);
-SpecialPowers.addPermission("contacts-create", true, document);
-
-var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
-var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
-                                  .getService(SpecialPowers.Ci.nsIPropertyBag2)
-                                  .getProperty('version');
-
-function onFailure() {
-  ok(false, "in on Failure!");
-  next();
-}
-
 var number1 = {
   local: "7932012345",
   international: "+557932012345"
 };
 
 var number2 = {
   local: "7932012346",
   international: "+557932012346"
@@ -67,23 +48,20 @@ var number3 = {
 };
 
 var properties3 = {
   name: ["Testname2"],
   tel: [{value: number3.international2}]
 };
 
 var req;
-var index = 0;
 var createResult1;
 var findResult1;
 var sample_id1;
 
-var mozContacts = window.navigator.mozContacts;
-
 var steps = [
   function () {
     ok(true, "Deleting database");
     req = mozContacts.clear();
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     };
@@ -280,34 +258,13 @@ var steps = [
     req.onerror = onFailure;
   },
   function () {
     ok(true, "all done!\n");
     SimpleTest.finish();
   }
 ];
 
-function next() {
-  ok(true, "Begin!");
-  if (index >= steps.length) {
-    ok(false, "Shouldn't get here!");
-    return;
-  }
-  try {
-    steps[index]();
-  } catch(ex) {
-    ok(false, "Caught exception", ex);
-  }
-  index += 1;
-}
-
-// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
-if (!isAndroid || androidVersion >= 14) {
-  SimpleTest.waitForExplicitFinish();
-  addLoadEvent(next);
-} else {
-  ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
-}
-
+start_tests();
 </script>
 </pre>
 </body>
 </html>
--- a/dom/contacts/tests/test_contacts_substringmatching.html
+++ b/dom/contacts/tests/test_contacts_substringmatching.html
@@ -12,69 +12,45 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=877302">Mozilla Bug 877302</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
+<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
 <script class="testbody" type="text/javascript">
-
 "use strict";
 
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
-}
-
 var substringLength = 8;
 SpecialPowers.setIntPref("dom.phonenumber.substringmatching.BR", substringLength);
 SpecialPowers.setCharPref("ril.lastKnownSimMcc", "724");
 
-SpecialPowers.addPermission("contacts-write", true, document);
-SpecialPowers.addPermission("contacts-read", true, document);
-SpecialPowers.addPermission("contacts-create", true, document);
-
-var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
-var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
-                                  .getService(SpecialPowers.Ci.nsIPropertyBag2)
-                                  .getProperty('version');
-
 var sample_id1;
 var createResult1;
 var findResult1;
 
-function onFailure() {
-  ok(false, "in on Failure!");
-  next();
-}
-
 var prop = {
   tel: [{value: "7932012345" }, {value: "7932012346"}]
 };
 
 var prop2 = {
   tel: [{value: "01187654321" }]
 };
 
 var prop3 = {
   tel: [{ value: "+43332112346" }]
 };
 
 var prop4 = {
   tel: [{ value: "(0414) 233-9888" }]
 };
 
-
 var req;
-var index = 0;
-
-var mozContacts = window.navigator.mozContacts;
-ok(mozContacts, "mozContacts exists");
-ok("mozContact" in window, "mozContact exists");
 var steps = [
   function () {
     ok(true, "Deleting database");
     req = mozContacts.clear()
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     }
@@ -319,34 +295,13 @@ var steps = [
   },
   function () {
     ok(true, "all done!\n");
     SpecialPowers.setIntPref("dom.phonenumber.substringmatching.BR", -1);
     SimpleTest.finish();
   }
 ];
 
-function next() {
-  ok(true, "Begin!");
-  if (index >= steps.length) {
-    ok(false, "Shouldn't get here!");
-    return;
-  }
-  try {
-    steps[index]();
-  } catch(ex) {
-    ok(false, "Caught exception", ex);
-  }
-  index += 1;
-}
-
-// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
-if (!isAndroid || androidVersion >= 14) {
-  SimpleTest.waitForExplicitFinish();
-  addLoadEvent(next);
-} else {
-  ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
-}
-
+start_tests();
 </script>
 </pre>
 </body>
 </html>
--- a/dom/contacts/tests/test_contacts_substringmatchingVE.html
+++ b/dom/contacts/tests/test_contacts_substringmatchingVE.html
@@ -12,60 +12,37 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=877302">Mozilla Bug 877302</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
+<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
 <script class="testbody" type="text/javascript">
-
 "use strict";
 
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
-}
-
 var substringLength = 7;
 SpecialPowers.setIntPref("dom.phonenumber.substringmatching.VE", substringLength);
 SpecialPowers.setCharPref("ril.lastKnownSimMcc", "734");
 
-SpecialPowers.addPermission("contacts-write", true, document);
-SpecialPowers.addPermission("contacts-read", true, document);
-SpecialPowers.addPermission("contacts-create", true, document);
-
-var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
-var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
-                                  .getService(SpecialPowers.Ci.nsIPropertyBag2)
-                                  .getProperty('version');
-
 var sample_id1;
 var createResult1;
 var findResult1;
 
-function onFailure() {
-  ok(false, "in on Failure!");
-  next();
-}
-
 var prop = {
   tel: [{value: "7932012345" }, {value: "7704143727591"}]
 };
 
 var prop2 = {
   tel: [{value: "7932012345" }, {value: "+58 212 5551212"}]
 };
 
 var req;
-var index = 0;
-
-var mozContacts = window.navigator.mozContacts;
-ok(mozContacts, "mozContacts exists");
-ok("mozContact" in window, "mozContact exists");
 var steps = [
   function () {
     ok(true, "Deleting database");
     req = mozContacts.clear()
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     }
@@ -147,34 +124,13 @@ var steps = [
   },
   function () {
     ok(true, "all done!\n");
     SpecialPowers.setIntPref("dom.phonenumber.substringmatching.VE", -1);
     SimpleTest.finish();
   }
 ];
 
-function next() {
-  ok(true, "Begin!");
-  if (index >= steps.length) {
-    ok(false, "Shouldn't get here!");
-    return;
-  }
-  try {
-    steps[index]();
-  } catch(ex) {
-    ok(false, "Caught exception", ex);
-  }
-  index += 1;
-}
-
-// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
-if (!isAndroid || androidVersion >= 14) {
-  SimpleTest.waitForExplicitFinish();
-  addLoadEvent(next);
-} else {
-  ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
-}
-
+start_tests();
 </script>
 </pre>
 </body>
 </html>
--- a/dom/network/src/NetworkStatsService.jsm
+++ b/dom/network/src/NetworkStatsService.jsm
@@ -29,20 +29,19 @@ const NET_TYPE_MOBILE = Ci.nsINetworkInt
 
 // The maximum traffic amount can be saved in the |cachedAppStats|.
 const MAX_CACHED_TRAFFIC = 500 * 1000 * 1000; // 500 MB
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageListenerManager");
 
-XPCOMUtils.defineLazyServiceGetter(this, "networkManager",
-                                   "@mozilla.org/network/manager;1",
-                                   "nsINetworkManager");
-
+XPCOMUtils.defineLazyServiceGetter(this, "gRil",
+                                   "@mozilla.org/ril;1",
+                                   "nsIRadioInterfaceLayer");
 
 XPCOMUtils.defineLazyServiceGetter(this, "networkService",
                                    "@mozilla.org/network/service;1",
                                    "nsINetworkService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "appsService",
                                    "@mozilla.org/AppsService;1",
                                    "nsIAppsService");
@@ -189,16 +188,30 @@ this.NetworkStatsService = {
    */
   notify: function(aTimer) {
     this.updateAllStats();
   },
 
   /*
    * nsINetworkStatsService
    */
+  getRilNetworks: function() {
+    let networks = {};
+    let numRadioInterfaces = gRil.numRadioInterfaces;
+    for (let i = 0; i < numRadioInterfaces; i++) {
+      let radioInterface = gRil.getRadioInterface(i);
+      if (radioInterface.rilContext.iccInfo) {
+        let netId = this.getNetworkId(radioInterface.rilContext.iccInfo.iccid,
+                                      NET_TYPE_MOBILE);
+        networks[netId] = { id : radioInterface.rilContext.iccInfo.iccid,
+                            type: NET_TYPE_MOBILE };
+      }
+    }
+    return networks;
+  },
 
   convertNetworkInterface: function(aNetwork) {
     if (aNetwork.type != NET_TYPE_MOBILE &&
         aNetwork.type != NET_TYPE_WIFI) {
       return null;
     }
 
     let id = '0';
@@ -224,17 +237,35 @@ this.NetworkStatsService = {
     return netId;
   },
 
   getNetworkId: function getNetworkId(aIccId, aNetworkType) {
     return aIccId + '' + aNetworkType;
   },
 
   getAvailableNetworks: function getAvailableNetworks(mm, msg) {
+    let self = this;
+    let rilNetworks = this.getRilNetworks();
     this._db.getAvailableNetworks(function onGetNetworks(aError, aResult) {
+
+      // Also return the networks that are valid but have not
+      // established connections yet.
+      for (let netId in rilNetworks) {
+        let found = false;
+        for (let i = 0; i < aResult.length; i++) {
+          if (netId == self.getNetworkId(aResult[i].id, aResult[i].type)) {
+            found = true;
+            break;
+          }
+        }
+        if (!found) {
+          aResult.push(rilNetworks[netId]);
+        }
+      }
+
       mm.sendAsyncMessage("NetworkStats:GetAvailableNetworks:Return",
                           { id: msg.id, error: aError, result: aResult });
     });
   },
 
   /*
    * Function called from manager to get stats from database.
    * In order to return updated stats, first is performed a call to
@@ -278,18 +309,33 @@ this.NetworkStatsService = {
         });
       });
       return;
     }
 
     // Check if the network is available in the DB. If yes, we also
     // retrieve the stats for it from the DB.
     this._db.isNetworkAvailable(network, function(aError, aResult) {
+      let toFind = false;
       if (aResult) {
-        // If network is not active, there is no need to update stats.
+        toFind = true;
+      } else if (!aError) {
+        // Network is not found in the database without any errors.
+        // Check if network is valid but has not established a connection yet.
+        let rilNetworks = self.getRilNetworks();
+        if (rilNetworks[netId]) {
+          // find will not get data for network from the database but will format the
+          // result object in order to make NetworkStatsManager be able to construct a
+          // nsIDOMMozNetworkStats object.
+          toFind = true;
+        }
+      }
+
+      if (toFind) {
+        // If network is not active, there is no need to update stats before finding.
         self._db.find(function onStatsFound(aError, aResult) {
           mm.sendAsyncMessage("NetworkStats:Get:Return",
                               { id: msg.id, error: aError, result: aResult });
         }, network, start, end, appId, manifestURL);
         return;
       }
 
       if (!aError) {
@@ -303,18 +349,28 @@ this.NetworkStatsService = {
 
   clearInterfaceStats: function clearInterfaceStats(mm, msg) {
     let network = msg.network;
     let netId = this.getNetworkId(network.id, network.type);
 
     debug("clear stats for network " + network.id + " of type " + network.type);
 
     if (!this._networks[netId]) {
+      let error = "Invalid networkType";
+      let result = null;
+
+      // Check if network is valid but has not established a connection yet.
+      let rilNetworks = this.getRilNetworks();
+      if (rilNetworks[netId]) {
+        error = null;
+        result = true;
+      }
+
       mm.sendAsyncMessage("NetworkStats:Clear:Return",
-                          { id: msg.id, error: "Invalid networkType", result: null });
+                          { id: msg.id, error: error, result: result });
       return;
     }
 
     this._db.clearInterfaceStats(network, function onDBCleared(aError, aResult) {
         mm.sendAsyncMessage("NetworkStats:Clear:Return",
                             { id: msg.id, error: aError, result: aResult });
     });
   },
--- a/layout/tools/reftest/b2g_start_script.js
+++ b/layout/tools/reftest/b2g_start_script.js
@@ -1,50 +1,70 @@
-args = __marionetteParams;
+/* 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/. */
+
+let serverAddr = __marionetteParams[0];
+let serverPort = __marionetteParams[1];
 
 function setDefaultPrefs() {
     // This code sets the preferences for extension-based reftest; for
     // command-line based reftest they are set in function handler_handle in
     // reftest-cmdline.js.  These two locations should stay in sync.
     //
     // FIXME: These should be in only one place.
-    var prefs = Components.classes["@mozilla.org/preferences-service;1"].
-                getService(Components.interfaces.nsIPrefService);
+    var prefs = Cc["@mozilla.org/preferences-service;1"].
+                getService(Ci.nsIPrefService);
     var branch = prefs.getDefaultBranch("");
     branch.setBoolPref("dom.use_xbl_scopes_for_remote_xul", false);
     branch.setBoolPref("gfx.color_management.force_srgb", true);
     branch.setBoolPref("browser.dom.window.dump.enabled", true);
     branch.setIntPref("ui.caretBlinkTime", -1);
     branch.setBoolPref("dom.send_after_paint_to_content", true);
     // no slow script dialogs
     branch.setIntPref("dom.max_script_run_time", 0);
     branch.setIntPref("dom.max_chrome_script_run_time", 0);
     branch.setIntPref("hangmonitor.timeout", 0);
     // Ensure autoplay is enabled for all platforms.
     branch.setBoolPref("media.autoplay.enabled", true);
     // Disable updates
     branch.setBoolPref("app.update.enabled", false);
+    // Disable addon updates and prefetching so we don't leak them
+    branch.setBoolPref("extensions.update.enabled", false);
+    branch.setBoolPref("extensions.getAddons.cache.enabled", false);
+    // Disable blocklist updates so we don't have them reported as leaks
+    branch.setBoolPref("extensions.blocklist.enabled", false);
+    // Make url-classifier updates so rare that they won't affect tests
+    branch.setIntPref("urlclassifier.updateinterval", 172800);
+    // Disable high-quality downscaling, since it makes reftests more difficult.
+    branch.setBoolPref("image.high_quality_downscaling.enabled", false);
+    // Checking whether two files are the same is slow on Windows.
+    // Setting this pref makes tests run much faster there.
+    branch.setBoolPref("security.fileuri.strict_origin_policy", false);
+    // Disable the thumbnailing service
+    branch.setBoolPref("browser.pagethumbnails.capturing_disabled", true);
 }
 
-function setPermissions(webserver, port) {
-  var perms = Components.classes["@mozilla.org/permissionmanager;1"]
-              .getService(Components.interfaces.nsIPermissionManager);
-  var ioService = Components.classes["@mozilla.org/network/io-service;1"]
-                  .getService(Components.interfaces.nsIIOService);
-  var uri = ioService.newURI("http://" + webserver + ":" + port, null, null);
-  perms.add(uri, "allowXULXBL", Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
+function setPermissions() {
+  let perms = Cc["@mozilla.org/permissionmanager;1"]
+              .getService(Ci.nsIPermissionManager);
+  let ioService = Cc["@mozilla.org/network/io-service;1"]
+                  .getService(Ci.nsIIOService);
+  let uri = ioService.newURI("http://" + serverAddr + ":" + serverPort, null, null);
+  perms.add(uri, "allowXULXBL", Ci.nsIPermissionManager.ALLOW_ACTION);
 }
 
 // Load into any existing windows
-let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
-                   .getService(Components.interfaces.nsIWindowMediator);
+let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator);
 let win = wm.getMostRecentWindow('');
 
 // Set preferences and permissions
 setDefaultPrefs();
-setPermissions(args[0], args[1]);
+setPermissions();
 
 // Loading this into the global namespace causes intermittent failures.
 // See bug 882888 for more details.
-let reftest = {}; Components.utils.import("chrome://reftest/content/reftest.jsm", reftest);
+let reftest = {};
+Cu.import("chrome://reftest/content/reftest.jsm", reftest);
 
 // Start the reftests
 reftest.OnRefTestLoad(win);
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -255,28 +255,29 @@ this.OnRefTestLoad = function OnRefTestL
     }
     if (gContainingWindow == null && win != null) {
       gContainingWindow = win;
     }
 
     if (gBrowserIsIframe) {
       gBrowser = gContainingWindow.document.createElementNS(XHTML_NS, "iframe");
       gBrowser.setAttribute("mozbrowser", "");
+      gBrowser.setAttribute("mozapp", prefs.getCharPref("browser.manifestURL"));
     } else {
       gBrowser = gContainingWindow.document.createElementNS(XUL_NS, "xul:browser");
     }
     gBrowser.setAttribute("id", "browser");
     gBrowser.setAttribute("type", "content-primary");
     gBrowser.setAttribute("remote", gBrowserIsRemote ? "true" : "false");
     // Make sure the browser element is exactly 800x1000, no matter
     // what size our window is
     gBrowser.setAttribute("style", "min-width: 800px; min-height: 1000px; max-width: 800px; max-height: 1000px");
 
-#if BOOTSTRAP
-#if REFTEST_B2G
+#ifdef BOOTSTRAP
+#ifdef REFTEST_B2G
     var doc = gContainingWindow.document.getElementsByTagName("html")[0];
 #else
     var doc = gContainingWindow.document.getElementById('main-window');
 #endif
     while (doc.hasChildNodes()) {
       doc.removeChild(doc.firstChild);
     }
     doc.appendChild(gBrowser);
@@ -327,18 +328,18 @@ function InitAndStartRefTests()
     try {
         var logFile = prefs.getCharPref("reftest.logFile");
         if (logFile) {
             try {
                 var f = FileUtils.File(logFile);
                 var mfl = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
                 // Set to mirror to stdout as well as the file
                 gDumpLog = function (msg) {
-#if BOOTSTRAP
-#if REFTEST_B2G
+#ifdef BOOTSTRAP
+#ifdef REFTEST_B2G
                     dump(msg);
 #else
                     //NOTE: on android-xul, we have a libc crash if we do a dump with %7s in the string
 #endif
 #else
                     dump(msg);
 #endif
                     mfl.write(msg, msg.length);
--- a/layout/tools/reftest/runreftestb2g.py
+++ b/layout/tools/reftest/runreftestb2g.py
@@ -399,26 +399,24 @@ class B2GReftest(RefTest):
         profile = RefTest.createReftestProfile(self, options, reftestlist,
                                                server=options.remoteWebServer,
                                                special_powers=False)
         profileDir = profile.profile
 
         prefs = {}
         # Turn off the locale picker screen
         prefs["browser.firstrun.show.localepicker"] = False
-        prefs["browser.homescreenURL"] = "app://system.gaiamobile.org"
-        prefs["browser.manifestURL"] = "app://system.gaiamobile.org/manifest.webapp"
+        prefs["browser.homescreenURL"] = "app://test-container.gaiamobile.org/index.html"
+        prefs["browser.manifestURL"] = "app://test-container.gaiamobile.org/manifest.webapp"
         prefs["browser.tabs.remote"] = False
-        prefs["dom.ipc.browser_frames.oop_by_default"] = True
         prefs["dom.ipc.tabs.disabled"] = False
         prefs["dom.mozBrowserFramesEnabled"] = True
-        prefs["dom.mozBrowserFramesWhitelist"] = "app://system.gaiamobile.org"
-        prefs["network.dns.localDomains"] = "app://system.gaiamobile.org"
         prefs["font.size.inflation.emPerLine"] = 0
         prefs["font.size.inflation.minTwips"] = 0
+        prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org"
         prefs["reftest.browser.iframe.enabled"] = False
         prefs["reftest.remote"] = True
         prefs["reftest.uri"] = "%s" % reftestlist
         # Set a future policy version to avoid the telemetry prompt.
         prefs["toolkit.telemetry.prompted"] = 999
         prefs["toolkit.telemetry.notifiedOptOut"] = 999
 
         # Set the extra prefs.
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -319,31 +319,23 @@ public:
 };
 
 bool
 GeckoPointerController::getBounds(float* outMinX,
                                   float* outMinY,
                                   float* outMaxX,
                                   float* outMaxY) const
 {
-    int32_t width, height, orientation;
-
     DisplayViewport viewport;
 
     mConfig->getDisplayInfo(false, &viewport);
 
     *outMinX = *outMinY = 0;
-    if (orientation == DISPLAY_ORIENTATION_90 ||
-        orientation == DISPLAY_ORIENTATION_270) {
-        *outMaxX = viewport.deviceHeight;
-        *outMaxY = viewport.deviceWidth;
-    } else {
-        *outMaxX = viewport.deviceWidth;
-        *outMaxY = viewport.deviceHeight;
-    }
+    *outMaxX = viewport.logicalRight;
+    *outMaxY = viewport.logicalBottom;
     return true;
 }
 
 void
 GeckoPointerController::move(float deltaX, float deltaY)
 {
     float minX, minY, maxX, maxY;
     getBounds(&minX, &minY, &maxX, &maxY);