Back out bug 813978. a=bustage
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Mon, 14 Jan 2013 17:37:54 -0800
changeset 118847 d97bca5db7470eee55d044541e4c84388f765be6
parent 118813 b04a7b0c22b616a08932fe6aee1e9b100438e643
child 118848 829470a09f03395c6e5dbeed9cb4b225af7f6a95
push id24180
push useremorley@mozilla.com
push dateTue, 15 Jan 2013 22:58:27 +0000
treeherdermozilla-central@72e34ce7fd92 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbustage
bugs813978
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Back out bug 813978. a=bustage
dom/sms/src/ril/SmsDatabaseService.js
dom/sms/tests/marionette/manifest.ini
dom/sms/tests/marionette/test_filter_mixed.js
--- a/dom/sms/src/ril/SmsDatabaseService.js
+++ b/dom/sms/src/ril/SmsDatabaseService.js
@@ -10,17 +10,17 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
 
 const RIL_SMSDATABASESERVICE_CONTRACTID = "@mozilla.org/sms/rilsmsdatabaseservice;1";
 const RIL_SMSDATABASESERVICE_CID = Components.ID("{a1fa610c-eb6c-4ac2-878f-b005d5e89249}");
 
 const DEBUG = false;
 const DB_NAME = "sms";
-const DB_VERSION = 7;
+const DB_VERSION = 6;
 const STORE_NAME = "sms";
 const MOST_RECENT_STORE_NAME = "most-recent";
 
 const DELIVERY_SENDING = "sending";
 const DELIVERY_RECEIVED = "received";
 
 const DELIVERY_STATUS_NOT_APPLICABLE = "not-applicable";
 const DELIVERY_STATUS_SUCCESS = "success";
@@ -190,20 +190,16 @@ SmsDatabaseService.prototype = {
           case 4:
             if (DEBUG) debug("Upgrade to version 5. Populate quick threads view.")
             self.upgradeSchema4(event.target.transaction);
             break;
           case 5:
             if (DEBUG) debug("Upgrade to version 6. Use PhonenumberJS.")
             self.upgradeSchema5(event.target.transaction);
             break;
-          case 6:
-            if (DEBUG) debug("Upgrade to version 7. Use multiple entry indexes.")
-            self.upgradeSchema6(event.target.transaction);
-            break;
           default:
             event.target.transaction.abort();
             callback("Old database version: " + event.oldVersion, null);
             break;
         }
         currentVersion++;
       }
     }
@@ -270,16 +266,19 @@ SmsDatabaseService.prototype = {
    * Create the initial database schema.
    *
    * TODO need to worry about number normalization somewhere...
    * TODO full text search on body???
    */
   createSchema: function createSchema(db) {
     // This objectStore holds the main SMS data.
     let objectStore = db.createObjectStore(STORE_NAME, { keyPath: "id" });
+    objectStore.createIndex("delivery", "delivery", { unique: false });
+    objectStore.createIndex("sender", "sender", { unique: false });
+    objectStore.createIndex("receiver", "receiver", { unique: false });
     objectStore.createIndex("timestamp", "timestamp", { unique: false });
     if (DEBUG) debug("Created object stores and indexes");
   },
 
   /**
    * Upgrade to the corresponding database schema version.
    */
   upgradeSchema: function upgradeSchema(objectStore) {
@@ -363,261 +362,99 @@ SmsDatabaseService.prototype = {
       cursor.continue();
     }
   },
 
   upgradeSchema5: function upgradeSchema5(transaction) {
     // Don't perform any upgrade. See Bug 819560.
   },
 
-  upgradeSchema6: function upgradeSchema6(transaction) {
-    let objectStore = transaction.objectStore(STORE_NAME);
-
-    // Delete "delivery" index.
-    if (objectStore.indexNames.contains("delivery")) {
-      objectStore.deleteIndex("delivery");
-    }
-    // Delete "sender" index.
-    if (objectStore.indexNames.contains("sender")) {
-      objectStore.deleteIndex("sender");
-    }
-    // Delete "receiver" index.
-    if (objectStore.indexNames.contains("receiver")) {
-      objectStore.deleteIndex("receiver");
-    }
-    // Delete "read" index.
-    if (objectStore.indexNames.contains("read")) {
-      objectStore.deleteIndex("read");
-    }
-
-    // Create new "delivery", "number" and "read" indexes.
-    objectStore.createIndex("delivery", "deliveryIndex");
-    objectStore.createIndex("number", "numberIndex", { multiEntry: true });
-    objectStore.createIndex("read", "readIndex");
-
-    // Populate new "deliverIndex", "numberIndex" and "readIndex" attributes.
-    objectStore.openCursor().onsuccess = function(event) {
-      let cursor = event.target.result;
-      if (!cursor) {
-        return;
-      }
-
-      let message = cursor.value;
-      let timestamp = message.timestamp;
-      message.deliveryIndex = [message.delivery, timestamp];
-      message.numberIndex = [
-        [message.sender, timestamp],
-        [message.receiver, timestamp]
-      ];
-      message.readIndex = [message.read, timestamp];
-      cursor.update(message);
-      cursor.continue();
+  /**
+   * Helper function to make the intersection of the partial result arrays
+   * obtained within createMessageList.
+   *
+   * @param keys
+   *        Object containing the partial result arrays.
+   * @param fiter
+   *        Object containing the filter search criteria used to retrieved the
+   *        partial results.
+   *
+   * return Array of keys containing the final result of createMessageList.
+   */
+  keyIntersection: function keyIntersection(keys, filter) {
+    // Always use keys[FILTER_TIMESTAMP] as base result set to be filtered.
+    // This ensures the result set is always sorted by timestamp.
+    let result = keys[FILTER_TIMESTAMP];
+    if (keys[FILTER_NUMBERS].length || filter.numbers) {
+      result = result.filter(function(i) {
+        return keys[FILTER_NUMBERS].indexOf(i) != -1;
+      });
     }
-  },
-
-  createMessageFromRecord: function createMessageFromRecord(record) {
-    if (DEBUG) debug("createMessageFromRecord: " + JSON.stringify(record));
-    return gSmsService.createSmsMessage(record.id,
-                                        record.delivery,
-                                        record.deliveryStatus,
-                                        record.sender,
-                                        record.receiver,
-                                        record.body,
-                                        record.messageClass,
-                                        record.timestamp,
-                                        record.read);
-  },
-
-  /**
-   * Queue up passed message id, reply if necessary. 'aMessageId' = 0 for no
-   * more messages, negtive for errors and valid otherwise.
-   */
-  onNextMessageInListGot: function onNextMessageInListGot(
-      aRequest, aObjectStore, aMessageList, aMessageId) {
-
-    if (DEBUG) debug("onNextMessageInListGot - " + aMessageId);
-    if (aMessageId) {
-      // Queue up any id but '0' and replies later accordingly.
-      aMessageList.results.push(aMessageId);
-    }
-    if (aMessageId <= 0) {
-      // No more processing.
-      aMessageList.processing = false;
-    }
-
-    if (!aMessageList.waitCount) {
-      if (DEBUG) debug("Cursor.continue() not called yet");
-      return;
+    if (keys[FILTER_DELIVERY].length || filter.delivery) {
+      result = result.filter(function(i) {
+        return keys[FILTER_DELIVERY].indexOf(i) != -1;
+      });
     }
-
-    aMessageList.waitCount -= 1;
-    if (!aMessageList.results.length) {
-      if (!aMessageList.processing) {
-        if (DEBUG) debug("No messages matching the filter criteria");
-        aRequest.notifyNoMessageInList();
-      }
-      return;
-    }
-
-    if (aMessageList.results[0] < 0) {
-      aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
-      return;
+    if (keys[FILTER_READ].length || filter.read) {
+      result = result.filter(function(i) {
+        return keys[FILTER_READ].indexOf(i) != -1;
+      });
     }
-
-    let firstMessageId = aMessageList.results.shift();
-    if (DEBUG) debug ("Fetching message " + firstMessageId);
-    let request = aObjectStore.get(aMessageId);
-    let self = this;
-    request.onsuccess = function onsuccess(event) {
-      let sms = self.createMessageFromRecord(event.target.result);
-      if (aMessageList.listId >= 0) {
-        if (DEBUG) debug("notifyNextMessageInListGot " + firstMessageId);
-        aRequest.notifyNextMessageInListGot(sms);
-      } else {
-        self.lastMessageListId += 1;
-        aMessageList.listId = self.lastMessageListId;
-        self.messageLists[self.lastMessageListId] = aMessageList;
-        if (DEBUG) debug("notifyMessageListCreated " + firstMessageId);
-        aRequest.notifyMessageListCreated(aMessageList.listId, sms);
-      }
-    }
-    request.onerror = function onerror(event) {
-      if (DEBUG) debug("notifyReadMessageListFailed " + firstMessageId);
-      aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
-    }
+    return result;
   },
 
   /**
-   * Queue up {aMessageId, aTimestamp} pairs, find out intersections and report
-   * to onNextMessageInListGot. Return true if it is still possible to have
-   * another match.
+   * Helper function called after createMessageList gets the final result array
+   * containing the list of primary keys of records that matches the provided
+   * search criteria. This function retrieves from the store the message with
+   * the primary key matching the first one in the message list array and keeps
+   * the rest of this array in memory. It also notifies via nsISmsRequest.
+   *
+   * @param messageList
+   *        Array of primary keys retrieved within createMessageList.
+   * @param request
+   *        A nsISmsRequest object.
    */
-  onNextMessageInMultiFiltersGot: function onNextMessageInMultiFiltersGot(
-      aRequest, aObjectStore, aMessageList, aWhich, aMessageId, aTimestamp) {
-
-    if (DEBUG) {
-      debug("onNextMessageInMultiFiltersGot: "
-            + aWhich + ", " + aMessageId + ", " + aTimestamp);
-    }
-    let filters = aMessageList.filters;
-
-    if (!aMessageId) {
-      filters[aWhich].processing = false;
-      for (let i = 0; i < filters.length; i++) {
-        if (filters[i].processing) {
-          return false;
-        }
-      }
-
-      this.onNextMessageInListGot(aRequest, aObjectStore, aMessageList, 0);
-      return false;
-    }
-
-    // Search id in other existing results. If no other results has it,
-    // and A) the last timestamp is smaller-equal to current timestamp,
-    // we wait for further results; either B) record timestamp is larger
-    // then current timestamp or C) no more processing for a filter, then we
-    // drop this id because there can't be a match anymore.
-    for (let i = 0; i < filters.length; i++) {
-      if (i == aWhich) continue;
-
-      let ctx = filters[i];
-      let results = ctx.results;
-      let found = false;
-      for (let j = 0; j < results.length; j++) {
-        let result = results[j];
-        if (result.id == aMessageId) {
-          found = true;
-          break;
-        }
-        if ((!aMessageList.reverse && (result.timestamp > aTimestamp)) ||
-            (aMessageList.reverse && (result.timestamp < aTimestamp))) {
-          // B) Cannot find a match anymore. Drop.
-          return true;
-        }
+  onMessageListCreated: function onMessageListCreated(messageList, aRequest) {
+    if (DEBUG) debug("Message list created: " + messageList);
+    let self = this;
+    self.newTxn(READ_ONLY, function (error, txn, store) {
+      if (error) {
+        aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
+        return;
       }
 
-      if (!found) {
-        if (!ctx.processing) {
-          // C) Cannot find a match anymore. Drop.
-          if (results.length) {
-            let lastResult = results[results.length - 1];
-            if ((!aMessageList.reverse && (lastResult.timestamp >= aTimestamp)) ||
-                (aMessageList.reverse && (lastResult.timestamp <= aTimestamp))) {
-              // Still have a chance to get another match. Return true.
-              return true;
-            }
-          }
-
-          // Impossible to find another match because all results in ctx have
-          // timestamps smaller than aTimestamp.
-          return this.onNextMessageInMultiFiltersGot(aRequest, aObjectStore,
-                                                     aMessageList, aWhich, 0, 0);
-        }
-
-        // A) Pending.
-        filters[aWhich].results.push({
-          id: aMessageId,
-          timestamp: aTimestamp
-        });
-        return true;
-      }
-    }
-
-    // Now id is found in all other results. Report it.
-    this.onNextMessageInListGot(aRequest, aObjectStore, aMessageList, aMessageId);
-    return true;
-  },
-
-  onNextMessageInMultiNumbersGot: function onNextMessageInMultiNumbersGot(
-      aRequest, aObjectStore, aMessageList, aWhich,
-      aSingleFilter, aIndex, aMessageId, aTimestamp) {
+      let messageId = messageList.shift();
+      if (DEBUG) debug ("Fetching message " + messageId);
+      let request = store.get(messageId);
+      let message;
+      request.onsuccess = function (event) {
+        message = request.result;
+      };
 
-    if (DEBUG) {
-      debug("onNextMessageInMultiNumbersGot: "
-            + aIndex + ", " + aMessageId + ", " + aTimestamp);
-    }
-    let queues = aMessageList.filters[aWhich].queues;
-    let q = queues[aIndex];
-    if (aMessageId) {
-      if (!aIndex) { // Timestamp.
-        q.results.push({
-          id: aMessageId,
-          timestamp: aTimestamp
-        });
-      } else { // Numbers.
-        q.results.push(aMessageId);
-      }
-      return true;
-    }
-
-    q.processing -= 1;
-    if (queues[0].processing || queues[1].processing) {
-      return false;
-    }
-
-    let tres = queues[0].results;
-    let qres = queues[1].results;
-    tres = tres.filter(function (element) {
-      return qres.indexOf(element.id) != -1;
+      txn.oncomplete = function oncomplete(event) {
+        if (DEBUG) debug("Transaction " + txn + " completed.");
+        if (!message) {
+          aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
+          return;
+        }
+        self.lastMessageListId += 1;
+        self.messageLists[self.lastMessageListId] = messageList;
+        let sms = gSmsService.createSmsMessage(message.id,
+                                               message.delivery,
+                                               message.deliveryStatus,
+                                               message.sender,
+                                               message.receiver,
+                                               message.body,
+                                               message.messageClass,
+                                               message.timestamp,
+                                               message.read);
+        aRequest.notifyMessageListCreated(self.lastMessageListId, sms);
+      };
     });
-    if (aSingleFilter) {
-      for (let i = 0; i < tres.length; i++) {
-        this.onNextMessageInListGot(aRequest, aObjectStore, aMessageList, tres[i].id);
-      }
-      this.onNextMessageInListGot(aRequest, aObjectStore, aMessageList, 0);
-    } else {
-      for (let i = 0; i < tres.length; i++) {
-        this.onNextMessageInMultiFiltersGot(aRequest, aObjectStore, aMessageList,
-                                            aWhich, tres[i].id, tres[i].timestamp);
-      }
-      this.onNextMessageInMultiFiltersGot(aRequest, aObjectStore, aMessageList,
-                                          aWhich, 0, 0);
-    }
-    return false;
   },
 
   saveMessage: function saveMessage(message) {
     this.lastKey += 1;
     message.id = this.lastKey;
     if (DEBUG) debug("Going to store " + JSON.stringify(message));
     this.newTxn(READ_WRITE, function(error, txn, stores) {
       if (error) {
@@ -685,30 +522,24 @@ SmsDatabaseService.prototype = {
     let sender = aSender;
     if (sender) {
       let parsedNumber = PhoneNumberUtils.parse(sender);
       sender = (parsedNumber && parsedNumber.internationalNumber)
                ? parsedNumber.internationalNumber
                : sender;
     }
 
-    let message = {
-      deliveryIndex:  [DELIVERY_RECEIVED, aDate],
-      numberIndex:    [[sender, aDate], [receiver, aDate]],
-      readIndex:      [FILTER_READ_UNREAD, aDate],
-
-      delivery:       DELIVERY_RECEIVED,
-      deliveryStatus: DELIVERY_STATUS_SUCCESS,
-      sender:         sender,
-      receiver:       receiver,
-      body:           aBody,
-      messageClass:   aMessageClass,
-      timestamp:      aDate,
-      read:           FILTER_READ_UNREAD
-    };
+    let message = {delivery:       DELIVERY_RECEIVED,
+                   deliveryStatus: DELIVERY_STATUS_SUCCESS,
+                   sender:         sender,
+                   receiver:       receiver,
+                   body:           aBody,
+                   messageClass:   aMessageClass,
+                   timestamp:      aDate,
+                   read:           FILTER_READ_UNREAD};
     return this.saveMessage(message);
   },
 
   saveSendingMessage: function saveSendingMessage(aReceiver, aBody, aDate) {
     let sender = this.mRIL.rilContext.icc ? this.mRIL.rilContext.icc.msisdn : null;
 
     // Workaround an xpconnect issue with undefined string objects.
     // See bug 808220
@@ -726,30 +557,24 @@ SmsDatabaseService.prototype = {
 
     if (sender) {
       let parsedNumber = PhoneNumberUtils.parse(sender.toString());
       sender = (parsedNumber && parsedNumber.internationalNumber)
                ? parsedNumber.internationalNumber
                : sender;
     }
 
-    let message = {
-      deliveryIndex:  [DELIVERY_SENDING, aDate],
-      numberIndex:    [[sender, aDate], [receiver, aDate]],
-      readIndex:      [FILTER_READ_READ, aDate],
-
-      delivery:       DELIVERY_SENDING,
-      deliveryStatus: DELIVERY_STATUS_PENDING,
-      sender:         sender,
-      receiver:       receiver,
-      body:           aBody,
-      messageClass:   MESSAGE_CLASS_NORMAL,
-      timestamp:      aDate,
-      read:           FILTER_READ_READ
-    };
+    let message = {delivery:       DELIVERY_SENDING,
+                   deliveryStatus: DELIVERY_STATUS_PENDING,
+                   sender:         sender,
+                   receiver:       receiver,
+                   body:           aBody,
+                   messageClass:   MESSAGE_CLASS_NORMAL,
+                   timestamp:      aDate,
+                   read:           FILTER_READ_READ};
     return this.saveMessage(message);
   },
 
   setMessageDelivery: function setMessageDelivery(messageId, delivery, deliveryStatus) {
     if (DEBUG) {
       debug("Setting message " + messageId + " delivery to " + delivery
             + ", and deliveryStatus to " + deliveryStatus);
     }
@@ -778,34 +603,32 @@ SmsDatabaseService.prototype = {
             && (message.deliveryStatus == deliveryStatus)) {
           if (DEBUG) {
             debug("The values of attribute delivery and deliveryStatus are the"
                   + " the same with given parameters.");
           }
           return;
         }
         message.delivery = delivery;
-        message.deliveryIndex = [delivery, message.timestamp];
         message.deliveryStatus = deliveryStatus;
         if (DEBUG) {
           debug("Message.delivery set to: " + delivery
                 + ", and Message.deliveryStatus set to: " + deliveryStatus);
         }
         store.put(message);
       };
     });
   },
 
   /**
    * nsISmsDatabaseService API
    */
 
   getMessage: function getMessage(messageId, aRequest) {
     if (DEBUG) debug("Retrieving message with ID " + messageId);
-    let self = this;
     this.newTxn(READ_ONLY, function (error, txn, store) {
       if (error) {
         if (DEBUG) debug(error);
         aRequest.notifyGetMessageFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
         return;
       }
       let request = store.mozGetAll(messageId);
 
@@ -825,18 +648,26 @@ SmsDatabaseService.prototype = {
         if (data.id != messageId) {
           if (DEBUG) {
             debug("Requested message ID (" + messageId + ") is " +
                   "different from the one we got");
           }
           aRequest.notifyGetMessageFailed(Ci.nsISmsRequest.UNKNOWN_ERROR);
           return;
         }
-        let sms = self.createMessageFromRecord(data);
-        aRequest.notifyMessageGot(sms);
+        let message = gSmsService.createSmsMessage(data.id,
+                                                   data.delivery,
+                                                   data.deliveryStatus,
+                                                   data.sender,
+                                                   data.receiver,
+                                                   data.body,
+                                                   data.messageClass,
+                                                   data.timestamp,
+                                                   data.read);
+        aRequest.notifyMessageGot(message);
       };
 
       txn.onerror = function onerror(event) {
         if (DEBUG) {
           if (event.target)
             debug("Caught error on transaction", event.target.errorCode);
         }
         //TODO look at event.target.errorCode, pick appropriate error constant
@@ -885,39 +716,54 @@ SmsDatabaseService.prototype = {
               // This must exist.
               let mostRecentEntry = event.target.result;
 
               if (!message.read) {
                 mostRecentEntry.unreadCount--;
               }
 
               if (mostRecentEntry.id == messageId) {
-                // Check most recent sender/receiver.
-                let numberRange = IDBKeyRange.bound([number, 0], [number, ""]);
-                let numberRequest = smsStore.index("number")
-                                            .openCursor(numberRange, PREV);
-                numberRequest.onsuccess = function(event) {
+                // This sucks, we have to find a new most-recent message.
+                message = null;
+
+                // Check most recent sender.
+                smsStore.index("sender").openCursor(number, "prev").onsuccess = function(event) {
+                  let cursor = event.target.result;
+                  if (cursor) {
+                    message = cursor.value;
+                  }
+                };
+
+                // Check most recent receiver.
+                smsStore.index("receiver").openCursor(number, "prev").onsuccess = function(event) {
                   let cursor = event.target.result;
-                  if (!cursor) {
+                  if (cursor) {
+                    if (!message || cursor.value.timeStamp > message.timestamp) {
+                      message = cursor.value;
+                    }
+                  }
+
+                  // If we found a new message then we need to update the data
+                  // in the most-recent store. Otherwise we can delete it.
+                  if (message) {
+                    mostRecentEntry.id = message.id;
+                    mostRecentEntry.timestamp = message.timestamp;
+                    mostRecentEntry.body = message.body;
+                    if (DEBUG) {
+                      debug("Updating mru entry: " +
+                            JSON.stringify(mostRecentEntry));
+                    }
+                    mruStore.put(mostRecentEntry);
+                  }
+                  else {
                     if (DEBUG) {
                       debug("Deleting mru entry for number '" + number + "'");
                     }
                     mruStore.delete(number);
-                    return;
                   }
-
-                  let nextMsg = cursor.value;
-                  mostRecentEntry.id = nextMsg.id;
-                  mostRecentEntry.timestamp = nextMsg.timestamp;
-                  mostRecentEntry.body = nextMsg.body;
-                  if (DEBUG) {
-                    debug("Updating mru entry: " +
-                          JSON.stringify(mostRecentEntry));
-                  }
-                  mruStore.put(mostRecentEntry);
                 };
               } else if (!message.read) {
                 // Shortcut, just update the unread count.
                 if (DEBUG) {
                   debug("Updating unread count for number '" + number + "': " +
                         (mostRecentEntry.unreadCount + 1) + " -> " +
                         mostRecentEntry.unreadCount);
                 }
@@ -937,336 +783,200 @@ SmsDatabaseService.prototype = {
       debug("Creating a message list. Filters:" +
             " startDate: " + filter.startDate +
             " endDate: " + filter.endDate +
             " delivery: " + filter.delivery +
             " numbers: " + filter.numbers +
             " read: " + filter.read +
             " reverse: " + reverse);
     }
+    // This object keeps the lists of keys retrieved by the search specific to
+    // each nsIMozSmsFilter. Once all the keys have been retrieved from the
+    // store, the final intersection of this arrays will contain all the
+    // keys for the message list that we are creating.
+    let filteredKeys = {};
+    filteredKeys[FILTER_TIMESTAMP] = [];
+    filteredKeys[FILTER_NUMBERS] = [];
+    filteredKeys[FILTER_DELIVERY] = [];
+    filteredKeys[FILTER_READ] = [];
+
+    // Callback function to iterate through request results via IDBCursor.
+    let successCb = function onsuccess(result, filter) {
+      // Once the cursor has retrieved all keys that matches its key range,
+      // the filter search is done.
+      if (!result) {
+        if (DEBUG) {
+          debug("These messages match the " + filter + " filter: " +
+                filteredKeys[filter]);
+        }
+        return;
+      }
+      // The cursor primaryKey is stored in its corresponding partial array
+      // according to the filter parameter.
+      let primaryKey = result.primaryKey;
+      filteredKeys[filter].push(primaryKey);
+      result.continue();
+    };
+
+    let errorCb = function onerror(event) {
+      //TODO look at event.target.errorCode, pick appropriate error constant.
+      if (DEBUG) debug("IDBRequest error " + event.target.errorCode);
+      aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
+      return;
+    };
 
     let self = this;
     this.newTxn(READ_ONLY, function (error, txn, store) {
       if (error) {
-        //TODO look at event.target.errorCode, pick appropriate error constant.
-        if (DEBUG) debug("IDBRequest error " + error.target.errorCode);
-        aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
+        errorCb(error);
         return;
       }
 
-      let messageList = {
-        listId: -1,
-        reverse: reverse,
-        processing: true,
-        stop: false,
-        // Local contexts for multiple filter targets' case.
-        filters: [],
-        // Pending message waiting count. Initialized with 1 for notifying
-        // message list created.
-        waitCount: 1,
-        results: []
+      // In first place, we retrieve the keys that match the filter.startDate
+      // and filter.endDate search criteria.
+      let timeKeyRange = null;
+      if (filter.startDate != null && filter.endDate != null) {
+        timeKeyRange = IDBKeyRange.bound(filter.startDate.getTime(),
+                                         filter.endDate.getTime());
+      } else if (filter.startDate != null) {
+        timeKeyRange = IDBKeyRange.lowerBound(filter.startDate.getTime());
+      } else if (filter.endDate != null) {
+        timeKeyRange = IDBKeyRange.upperBound(filter.endDate.getTime());
+      }
+      let direction = reverse ? PREV : NEXT;
+      let timeRequest = store.index("timestamp").openKeyCursor(timeKeyRange,
+                                                               direction);
+
+      timeRequest.onsuccess = function onsuccess(event) {
+        successCb(event.target.result, FILTER_TIMESTAMP);
       };
+      timeRequest.onerror = errorCb;
 
-      let onNextMessageInListGotCb =
-        self.onNextMessageInListGot.bind(self, aRequest, store, messageList);
+      // Retrieve the keys from the 'delivery' index that matches the
+      // value of filter.delivery.
+      if (filter.delivery) {
+        let deliveryKeyRange = IDBKeyRange.only(filter.delivery);
+        let deliveryRequest = store.index("delivery")
+                                   .openKeyCursor(deliveryKeyRange);
+        deliveryRequest.onsuccess = function onsuccess(event) {
+          successCb(event.target.result, FILTER_DELIVERY);
+        };
+        deliveryRequest.onerror = errorCb;
+      }
 
-      let singleFilterSuccessCb = function onSingleFilterSuccess(event) {
-        if (messageList.stop) {
-          return;
+      // Retrieve the keys from the 'sender' and 'receiver' indexes that
+      // match the values of filter.numbers
+      if (filter.numbers) {
+        for (let i = 0; i < filter.numbers.length; i++) {
+          let numberKeyRange = IDBKeyRange.only(filter.numbers[i]);
+          let senderRequest = store.index("sender")
+                                   .openKeyCursor(numberKeyRange);
+          let receiverRequest = store.index("receiver")
+                                     .openKeyCursor(numberKeyRange);
+          senderRequest.onsuccess = receiverRequest.onsuccess =
+            function onsuccess(event){
+              successCb(event.target.result, FILTER_NUMBERS);
+            };
+          senderRequest.onerror = receiverRequest.onerror = errorCb;
         }
+      }
 
-        let cursor = event.target.result;
-        // Once the cursor has retrieved all keys that matches its key range,
-        // the filter search is done.
-        if (cursor) {
-          onNextMessageInListGotCb(cursor.primaryKey);
-          cursor.continue();
-        } else {
-          onNextMessageInListGotCb(0);
-        }
-      };
+      // Retrieve the keys from the 'read' index that matches the value of
+      // filter.read
+      if (filter.read != undefined) {
+        let read = filter.read ? FILTER_READ_READ : FILTER_READ_UNREAD;
+        if (DEBUG) debug("filter.read " + read);
+        let readKeyRange = IDBKeyRange.only(read);
+        let readRequest = store.index("read")
+                               .openKeyCursor(readKeyRange);
+        readRequest.onsuccess = function onsuccess(event) {
+          successCb(event.target.result, FILTER_READ);
+        };
+        readRequest.onerror = errorCb;
+      }
 
-      let singleFilterErrorCb = function onSingleFilterError(event) {
-        if (messageList.stop) {
+      txn.oncomplete = function oncomplete(event) {
+        if (DEBUG) debug("Transaction " + txn + " completed.");
+        // We need to get the intersection of all the partial searches to
+        // get the final result array.
+        let result =  self.keyIntersection(filteredKeys, filter);
+        if (!result.length) {
+          if (DEBUG) debug("No messages matching the filter criteria");
+          aRequest.notifyNoMessageInList();
           return;
         }
 
-        if (DEBUG) debug("IDBRequest error " + event.target.errorCode);
-        onNextMessageInListGotCb(-1);
+        // At this point, filteredKeys should have all the keys that matches
+        // all the search filters. So we take the first key and retrieve the
+        // corresponding message. The rest of the keys are added to the
+        // messageLists object as a new list.
+        self.onMessageListCreated(result, aRequest);
       };
 
-      let direction = reverse ? PREV : NEXT;
-
-      // We support filtering by date range only (see `else` block below) or
-      // by number/delivery status/read status with an optional date range.
-      if (filter.delivery || filter.numbers || filter.read != undefined) {
-        let multiFiltersGotCb = self.onNextMessageInMultiFiltersGot
-                                    .bind(self, aRequest, store, messageList);
-
-        let multiFiltersSuccessCb = function onMultiFiltersSuccess(which, event) {
-          if (messageList.stop) {
-            return;
-          }
-
-          let cursor = event.target.result;
-          if (cursor) {
-            if (multiFiltersGotCb(which, cursor.primaryKey, cursor.key[1])) {
-              cursor.continue();
-            }
-          } else {
-            multiFiltersGotCb(which, 0, 0);
-          }
-        };
-
-        let multiFiltersErrorCb = function onMultiFiltersError(which, event) {
-          if (messageList.stop) {
-            return;
-          }
-
-          // Act as no more matched records.
-          multiFiltersGotCb(which, 0, 0);
-        };
-
-        // Numeric 0 is smaller than any time stamp, and empty string is larger
-        // than all numeric values.
-        let startDate = 0, endDate = "";
-        if (filter.startDate != null) {
-          startDate = filter.startDate.getTime();
-        }
-        if (filter.endDate != null) {
-          endDate = filter.endDate.getTime();
-        }
-
-        let singleFilter;
-        {
-          let numFilterTargets = 0;
-          if (filter.delivery) numFilterTargets++;
-          if (filter.numbers) numFilterTargets++;
-          if (filter.read != undefined) numFilterTargets++;
-          singleFilter = numFilterTargets == 1;
-        }
-
-        let which = 0;
-
-        let createRangedRequest = function createRangedRequest(indexName, key) {
-          let range = IDBKeyRange.bound([key, startDate], [key, endDate]);
-          return store.index(indexName).openKeyCursor(range, direction);
-        };
-
-        let createSimpleRangedRequest =
-            function createSimpleRangedRequest(indexName, key) {
-          let request = createRangedRequest(indexName, key);
-          if (singleFilter) {
-            request.onsuccess = singleFilterSuccessCb;
-            request.onerror = singleFilterErrorCb;
-          } else {
-            let me = which++;
-            messageList.filters.push({
-              processing: true,
-              results: []
-            });
-            request.onsuccess = multiFiltersSuccessCb.bind(null, me);
-            request.onerror = multiFiltersErrorCb.bind(null, me);
-          }
-        };
-
-        // Retrieve the keys from the 'delivery' index that matches the
-        // value of filter.delivery.
-        if (filter.delivery) {
-          if (DEBUG) debug("filter.delivery " + filter.delivery);
-          createSimpleRangedRequest("delivery", filter.delivery);
-        }
-
-        // Retrieve the keys from the 'sender' and 'receiver' indexes that
-        // match the values of filter.numbers
-        if (filter.numbers) {
-          if (DEBUG) debug("filter.numbers " + filter.numbers.join(", "));
-          let me = which++;
-
-          let multiNumbersGotCb = self.onNextMessageInMultiNumbersGot
-                                      .bind(self, aRequest, store, messageList,
-                                            me, singleFilter);
-
-          let multiNumbersSuccessCb = function onMultiNumbersSuccess(index, event) {
-            if (messageList.stop) {
-              return;
-            }
-
-            let cursor = event.target.result;
-            if (cursor) {
-              if (multiNumbersGotCb(index, cursor.primaryKey,
-                                    index ? cursor.key[1] : cursor.key)) {
-                cursor.continue();
-              }
-            } else {
-              multiNumbersGotCb(index, 0, 0);
-            }
-          };
-
-          let multiNumbersErrorCb = function onMultiNumbersError(index, event) {
-            if (messageList.stop) {
-              return;
-            }
-
-            // Act as no more matched records.
-            multiNumbersGotCb(index, 0, 0);
-          };
-
-          let ctx = {};
-          if (!singleFilter) {
-            ctx.processing = true;
-            ctx.results = [];
-          }
-
-          let multiNumbers = filter.numbers.length > 1;
-          if (multiNumbers) {
-            ctx.queues = [];
-            // For timestamp.
-            let range = null;
-            if (filter.startDate != null && filter.endDate != null) {
-              range = IDBKeyRange.bound(filter.startDate.getTime(),
-                                        filter.endDate.getTime());
-            } else if (filter.startDate != null) {
-              range = IDBKeyRange.lowerBound(filter.startDate.getTime());
-            } else if (filter.endDate != null) {
-              range = IDBKeyRange.upperBound(filter.endDate.getTime());
-            }
-
-            let request = store.index("timestamp")
-                               .openKeyCursor(range, direction);
-            request.onsuccess = multiNumbersSuccessCb.bind(null, 0);
-            request.onerror = multiNumbersErrorCb.bind(null, 0);
-
-            ctx.queues.push({
-              processing: 1,
-              results: []
-            });
-            // For all numbers.
-            ctx.queues.push({
-              processing: filter.numbers.length,
-              results: []
-            });
-          }
-
-          messageList.filters.push(ctx);
-
-          for (let i = 0; i < filter.numbers.length; i++) {
-            let request = createRangedRequest("number", filter.numbers[i]);
-            if (multiNumbers) {
-              request.onsuccess = multiNumbersSuccessCb.bind(null, 1);
-              request.onerror = multiNumbersErrorCb.bind(null, 1);
-            } else if (singleFilter) {
-              request.onsuccess = singleFilterSuccessCb;
-              request.onerror = singleFilterErrorCb;
-            } else {
-              request.onsuccess = multiFiltersSuccessCb.bind(null, me);
-              request.onerror = multiFiltersErrorCb.bind(null, me);
-            }
-          }
-        }
-
-        // Retrieve the keys from the 'read' index that matches the value of
-        // filter.read
-        if (filter.read != undefined) {
-          let read = filter.read ? FILTER_READ_READ : FILTER_READ_UNREAD;
-          if (DEBUG) debug("filter.read " + read);
-          createSimpleRangedRequest("read", read);
-        }
-      } else {
-        // Filtering by date range only.
-        if (DEBUG) {
-          debug("filter.timestamp " + filter.startDate + ", " + filter.endDate);
-        }
-
-        let range = null;
-        if (filter.startDate != null && filter.endDate != null) {
-          range = IDBKeyRange.bound(filter.startDate.getTime(),
-                                    filter.endDate.getTime());
-        } else if (filter.startDate != null) {
-          range = IDBKeyRange.lowerBound(filter.startDate.getTime());
-        } else if (filter.endDate != null) {
-          range = IDBKeyRange.upperBound(filter.endDate.getTime());
-        }
-
-        let request = store.index("timestamp").openKeyCursor(range, direction);
-        request.onsuccess = singleFilterSuccessCb;
-        request.onerror = singleFilterErrorCb;
-      }
-
-      if (DEBUG) {
-        txn.oncomplete = function oncomplete(event) {
-          debug("Transaction " + txn + " completed.");
-        };
-      }
-
-      txn.onerror = singleFilterErrorCb;
+      txn.onerror = function onerror(event) {
+        errorCb(event);
+      };
     });
   },
 
   getNextMessageInList: function getNextMessageInList(listId, aRequest) {
     if (DEBUG) debug("Getting next message in list " + listId);
     let messageId;
     let list = this.messageLists[listId];
     if (!list) {
       if (DEBUG) debug("Wrong list id");
       aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.NOT_FOUND_ERROR);
       return;
     }
-    if (list.processing) {
-      // Database transaction ongoing, let it reply for us so that we won't get
-      // blocked by the existing transaction.
-      list.waitCount++;
-      return;
-    }
-    if (!list.results.length) {
+    messageId = list.shift();
+    if (messageId == null) {
       if (DEBUG) debug("Reached the end of the list!");
       aRequest.notifyNoMessageInList();
       return;
     }
-    if (list.results[0] < 0) {
-      aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
-      return;
-    }
-    messageId = list.results.shift();
-    let self = this;
     this.newTxn(READ_ONLY, function (error, txn, store) {
       if (DEBUG) debug("Fetching message " + messageId);
       let request = store.get(messageId);
       let message;
       request.onsuccess = function onsuccess(event) {
         message = request.result;
       };
 
       txn.oncomplete = function oncomplete(event) {
         if (DEBUG) debug("Transaction " + txn + " completed.");
         if (!message) {
           if (DEBUG) debug("Could not get message id " + messageId);
           aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.NOT_FOUND_ERROR);
         }
-        let sms = self.createMessageFromRecord(message);
+        let sms = gSmsService.createSmsMessage(message.id,
+                                               message.delivery,
+                                               message.deliveryStatus,
+                                               message.sender,
+                                               message.receiver,
+                                               message.body,
+                                               message.messageClass,
+                                               message.timestamp,
+                                               message.read);
         aRequest.notifyNextMessageInListGot(sms);
       };
 
       txn.onerror = function onerror(event) {
         //TODO check event.target.errorCode
         if (DEBUG) {
           debug("Error retrieving message id: " + messageId +
                 ". Error code: " + event.target.errorCode);
         }
         aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
       };
     });
   },
 
   clearMessageList: function clearMessageList(listId) {
     if (DEBUG) debug("Clearing message list: " + listId);
-    if (this.messageLists[listId]) {
-      this.messageLists[listId].stop = true;
-      delete this.messageLists[listId];
-    }
+    delete this.messageLists[listId];
   },
 
   markMessageRead: function markMessageRead(messageId, value, aRequest) {
     if (DEBUG) debug("Setting message " + messageId + " read to " + value);
     this.newTxn(READ_WRITE, function (error, txn, stores) {
       if (error) {
         if (DEBUG) debug(error);
         aRequest.notifyMarkMessageReadFailed(Ci.nsISmsRequest.INTERNAL_ERROR);
@@ -1294,17 +1004,16 @@ SmsDatabaseService.prototype = {
         // If the value to be set is the same as the current message `read`
         // value, we just notify successfully.
         if (message.read == value) {
           if (DEBUG) debug("The value of message.read is already " + value);
           aRequest.notifyMessageMarkedRead(message.read);
           return;
         }
         message.read = value ? FILTER_READ_READ : FILTER_READ_UNREAD;
-        message.readIndex = [message.read, message.timestamp];
         if (DEBUG) debug("Message.read set to: " + value);
         event.target.source.put(message).onsuccess = function onsuccess(event) {
           if (DEBUG) {
             debug("Update successfully completed. Message: " +
                   JSON.stringify(event.target.result));
           }
 
           // Now update the unread count.
--- a/dom/sms/tests/marionette/manifest.ini
+++ b/dom/sms/tests/marionette/manifest.ini
@@ -16,15 +16,14 @@ qemu = true
 [test_filter_date.js]
 [test_filter_date_notfound.js]
 [test_filter_number_single.js]
 [test_filter_number_multiple.js]
 [test_filter_received.js]
 [test_filter_sent.js]
 [test_filter_read.js]
 [test_filter_unread.js]
-[test_filter_mixed.js]
 [test_segment_info.js]
 [test_mark_msg_read.js]
 [test_mark_msg_read_error.js]
 [test_bug814761.js]
 [test_strict_7bit_encoding.js]
 disabled = Bug 828633
deleted file mode 100644
--- a/dom/sms/tests/marionette/test_filter_mixed.js
+++ /dev/null
@@ -1,338 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_TIMEOUT = 40000;
-
-const SELF = 5554;
-const NUM_THREADS = 10;
-
-SpecialPowers.addPermission("sms", true, document);
-SpecialPowers.setBoolPref("dom.sms.enabled", true);
-
-let sms = window.navigator.mozSms;
-ok(sms instanceof MozSmsManager);
-
-let pendingEmulatorCmdCount = 0;
-function sendSmsToEmulator(from, text) {
-  ++pendingEmulatorCmdCount;
-
-  let cmd = "sms send " + from + " " + text;
-  runEmulatorCmd(cmd, function (result) {
-    --pendingEmulatorCmdCount;
-
-    is(result[0], "OK", "Emulator response");
-  });
-}
-
-function getAllMessages(callback, filter, reverse) {
-  if (!filter) {
-    filter = new MozSmsFilter;
-  }
-  let messages = [];
-  let request = sms.getMessages(filter, reverse || false);
-  request.onsuccess = function(event) {
-    let cursor = event.target.result;
-    if (cursor.message) {
-      messages.push(cursor.message);
-      cursor.continue();
-      return;
-    }
-
-    window.setTimeout(callback.bind(null, messages), 0);
-  }
-}
-
-function deleteAllMessages(next) {
-  getAllMessages(function deleteAll(messages) {
-    let message = messages.shift();
-    if (!message) {
-      ok(true, "all messages deleted");
-      window.setTimeout(next, 0);
-      return;
-    }
-
-    let request = sms.delete(message.id);
-    request.onsuccess = deleteAll.bind(null, messages);
-    request.onerror = function (event) {
-      ok(false, "failed to delete all messages");
-      window.setTimeout(cleanUp, 0);
-    }
-  });
-}
-
-/**
- * Populate SmsDatabase with messages to being tests. We'll have NUM_THREADS
- * sent and received messages, and NUM_THREADS/2 unread received messages.
- *
- *   send    to   "0"
- *   receive from "0", count = 1
- *   mark         received as read
- *
- *   send    to   "1"
- *   receive from "1", count = 2
- *
- *   send    to   "2"
- *   receive from "2", count = 3
- *   mark         received as read
- *   ...
- *   send    to   "9"
- *   receive from "9", count = 10
- */
-function populateMessages() {
-  let count = 0;
-
-  function sendMessage(iter) {
-    let request = sms.send("" + iter, "Nice to meet you");
-    request.onsuccess = function onRequestSuccess(event) {
-      sms.addEventListener("received", onReceived);
-      sendSmsToEmulator("" + iter, "Nice to meet you, too");
-    }
-    request.onerror = function onRequestError(event) {
-      window.setTimeout(deleteAllMessages.bind(null, cleanUp), 0);
-    }
-  }
-
-  function onReceived(event) {
-    sms.removeEventListener("received", onReceived);
-
-    ++count;
-    if (count % 2) {
-      let request = sms.markMessageRead(event.message.id, true);
-      request.onsuccess = function onRequestSuccess(event) {
-        if (count < NUM_THREADS) {
-          sendMessage(count);
-        } else {
-          window.setTimeout(testDeliveryAndNumber, 0);
-        }
-      }
-      request.onerror = function onRequestError(event) {
-        window.setTimeout(deleteAllMessages.bind(null, cleanUp), 0);
-      }
-    } else if (count < NUM_THREADS) {
-      sendMessage(count);
-    } else {
-      window.setTimeout(testDeliveryAndNumber, 0);
-    }
-  }
-
-  sendMessage(count);
-}
-
-function testDeliveryAndNumber() {
-  log("Checking delivery == sent && number == 0");
-  let filter = new MozSmsFilter();
-  filter.delivery = "sent";
-  filter.numbers = ["0"];
-  getAllMessages(function (messages) {
-    // Only { delivery: "sent", receiver: "0", read: true }
-    is(messages.length, 1, "message count");
-    for (let i = 0; i < messages.length; i++) {
-      let message = messages[i];
-      is(message.delivery, filter.delivery, "message delivery");
-      if (!((message.sender == filter.numbers[0])
-            || (message.receiver == filter.numbers[0]))) {
-        ok(false, "message sendor or receiver number");
-      }
-    }
-
-    getAllMessages(function (messages_r) {
-      is(messages.length, messages_r.length, "message count");
-      for (let i = 0; i < messages_r.length; i++) {
-        is(messages_r[i].id, messages[messages.length - 1 - i].id, "message id");
-      }
-
-      window.setTimeout(testDeliveryAndNumberNotFound, 0);
-    }, filter, true);
-  }, filter);
-}
-
-function testDeliveryAndNumberNotFound() {
-  log("Checking delivery == sent && number == 12345");
-  let filter = new MozSmsFilter();
-  filter.delivery = "sent";
-  filter.numbers = ["12345"];
-  getAllMessages(function (messages) {
-    is(messages.length, 0, "message count");
-
-    window.setTimeout(testDeliveryAndRead, 0);
-  }, filter);
-}
-
-function testDeliveryAndRead() {
-  log("Checking delivery == received && read == true");
-  let filter = new MozSmsFilter();
-  filter.delivery = "received";
-  filter.read = true;
-  getAllMessages(function (messages) {
-    // { delivery: "received", sender: "0", read: true },
-    // { delivery: "received", sender: "2", read: true },
-    // { delivery: "received", sender: "4", read: true },
-    // { delivery: "received", sender: "6", read: true }, and
-    // { delivery: "received", sender: "8", read: true },
-    is(messages.length, NUM_THREADS / 2, "message count");
-    for (let i = 0; i < messages.length; i++) {
-      let message = messages[i];
-      is(message.delivery, filter.delivery, "message delivery");
-      is(message.read, filter.read, "message read");
-    }
-
-    getAllMessages(function (messages_r) {
-      is(messages.length, messages_r.length, "message count");
-      for (let i = 0; i < messages_r.length; i++) {
-        is(messages_r[i].id, messages[messages.length - 1 - i].id, "message id");
-      }
-
-      window.setTimeout(testDeliveryAndReadNotFound, 0);
-    }, filter, true);
-  }, filter);
-}
-
-function testDeliveryAndReadNotFound() {
-  log("Checking delivery == sent && read == false");
-  let filter = new MozSmsFilter();
-  filter.delivery = "sent";
-  filter.read = false;
-  getAllMessages(function (messages) {
-    is(messages.length, 0, "message count");
-
-    window.setTimeout(testNumberAndRead, 0);
-  }, filter);
-}
-
-function testNumberAndRead() {
-  log("Checking number == 0 && read == true");
-  let filter = new MozSmsFilter();
-  filter.numbers = ["0"];
-  filter.read = true;
-  getAllMessages(function (messages) {
-    // { delivery: "sent", receiver: "0", read: true }, and
-    // { delivery: "received", sender: "0", read: true }
-    is(messages.length, 2, "message count");
-    for (let i = 0; i < messages.length; i++) {
-      let message = messages[i];
-      if (!((message.sender == filter.numbers[0])
-            || (message.receiver == filter.numbers[0]))) {
-        ok(false, "message sendor or receiver number");
-      }
-      is(message.read, filter.read, "message read");
-    }
-
-    getAllMessages(function (messages_r) {
-      is(messages.length, messages_r.length, "message count");
-      for (let i = 0; i < messages_r.length; i++) {
-        is(messages_r[i].id, messages[messages.length - 1 - i].id, "message id");
-      }
-
-      window.setTimeout(testNumberAndReadNotFound, 0);
-    }, filter, true);
-  }, filter);
-}
-
-function testNumberAndReadNotFound() {
-  log("Checking number == 12345 && read == true");
-  let filter = new MozSmsFilter();
-  filter.numbers = ["12345"];
-  filter.read = true;
-  getAllMessages(function (messages) {
-    is(messages.length, 0, "message count");
-
-    window.setTimeout(testMultipleNumbers, 0);
-  }, filter);
-}
-
-function testMultipleNumbers() {
-  log("Checking number == 0 || number == 1");
-  let filter = new MozSmsFilter();
-  filter.numbers = ["0", "1"];
-  getAllMessages(function (messages) {
-    // { delivery: "sent", receiver: "0", read: true }
-    // { delivery: "received", sender: "0", read: true }
-    // { delivery: "sent", receiver: "1", read: true }
-    // { delivery: "received", sender: "1", read: false }
-    is(messages.length, 4, "message count");
-    for (let i = 0; i < messages.length; i++) {
-      let message = messages[i];
-      if (!((message.sender == filter.numbers[0])
-            || (message.receiver == filter.numbers[0])
-            || (message.sender == filter.numbers[1])
-            || (message.receiver == filter.numbers[1]))) {
-        ok(false, "message sendor or receiver number");
-      }
-    }
-
-    window.setTimeout(testMultipleNumbersNotFound, 0);
-  }, filter);
-}
-
-function testMultipleNumbersNotFound() {
-  log("Checking number == 12345 || number == 6789");
-  let filter = new MozSmsFilter();
-  filter.numbers = ["12345", "6789"];
-  getAllMessages(function (messages) {
-    is(messages.length, 0, "message count");
-
-    window.setTimeout(testDeliveryAndMultipleNumbers, 0);
-  }, filter);
-}
-
-function testDeliveryAndMultipleNumbers() {
-  log("Checking delivery == sent && (number == 0 || number == 1)");
-  let filter = new MozSmsFilter();
-  filter.delivery = "sent";
-  filter.numbers = ["0", "1"];
-  getAllMessages(function (messages) {
-    // { delivery: "sent", receiver: "0", read: true }
-    // { delivery: "sent", receiver: "1", read: true }
-    is(messages.length, 2, "message count");
-    for (let i = 0; i < messages.length; i++) {
-      let message = messages[i];
-      is(message.delivery, filter.delivery, "message delivery");
-      if (!((message.sender == filter.numbers[0])
-            || (message.receiver == filter.numbers[0])
-            || (message.sender == filter.numbers[1])
-            || (message.receiver == filter.numbers[1]))) {
-        ok(false, "message sendor or receiver number");
-      }
-    }
-
-    window.setTimeout(testMultipleNumbersAndRead, 0);
-  }, filter);
-}
-
-function testMultipleNumbersAndRead() {
-  log("Checking (number == 0 || number == 1) && read == true");
-  let filter = new MozSmsFilter();
-  filter.numbers = ["0", "1"];
-  filter.read = true;
-  getAllMessages(function (messages) {
-    // { delivery: "sent", receiver: "0", read: true }
-    // { delivery: "received", sender: "0", read: true }
-    // { delivery: "sent", receiver: "1", read: true }
-    is(messages.length, 3, "message count");
-    for (let i = 0; i < messages.length; i++) {
-      let message = messages[i];
-      is(message.read, filter.read, "message read");
-      if (!((message.sender == filter.numbers[0])
-            || (message.receiver == filter.numbers[0])
-            || (message.sender == filter.numbers[1])
-            || (message.receiver == filter.numbers[1]))) {
-        ok(false, "message sendor or receiver number");
-      }
-    }
-
-    window.setTimeout(deleteAllMessages.bind(null, cleanUp), 0);
-  }, filter);
-}
-
-function cleanUp() {
-  if (pendingEmulatorCmdCount) {
-    window.setTimeout(cleanUp, 100);
-    return;
-  }
-
-  SpecialPowers.removePermission("sms", document);
-  SpecialPowers.clearUserPref("dom.sms.enabled");
-  finish();
-}
-
-deleteAllMessages(populateMessages);