Bug 850430 - Handle Date properties consistently across the Contacts code. r=gwagner
authorReuben Morais <reuben.morais@gmail.com>
Fri, 18 Oct 2013 03:11:10 -0300
changeset 165142 caa15ceeba4b4c703f8fd7717580d2e369653888
parent 165141 dad5d17328b2eecbc28e4c10b9fc6cdc30526beb
child 165143 3a55fecc7454cfd972c1ec88b30d09c079bd0710
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgwagner
bugs850430
milestone27.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
Bug 850430 - Handle Date properties consistently across the Contacts code. r=gwagner
dom/contacts/ContactManager.js
dom/contacts/fallback/ContactDB.jsm
dom/webidl/Contacts.webidl
mobile/android/base/ContactService.java
mobile/android/modules/ContactService.jsm
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -389,22 +389,16 @@ ContactManager.prototype = {
     this.__DOM_IMPL__.setEventHandler("oncontactchange", aHandler);
   },
 
   get oncontactchange() {
     return this.__DOM_IMPL__.getEventHandler("oncontactchange");
   },
 
   _convertContact: function(aContact) {
-    if (aContact.properties.bday) {
-      aContact.properties.bday = new Date(aContact.properties.bday);
-    }
-    if (aContact.properties.anniversary) {
-      aContact.properties.anniversary = new Date(aContact.properties.anniversary);
-    }
     let newContact = new this._window.mozContact(aContact.properties);
     newContact.setMetadata(aContact.id, aContact.published, aContact.updated);
     return newContact;
   },
 
   _convertContacts: function(aContacts) {
     let contacts = [];
     for (let i in aContacts) {
--- a/dom/contacts/fallback/ContactDB.jsm
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -15,23 +15,33 @@ const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
 
 const DB_NAME = "contacts";
-const DB_VERSION = 15;
+const DB_VERSION = 16;
 const STORE_NAME = "contacts";
 const SAVED_GETALL_STORE_NAME = "getallcache";
 const CHUNK_SIZE = 20;
 const REVISION_STORE = "revision";
 const REVISION_KEY = "revision";
 
+function optionalDate(aValue) {
+  if (aValue) {
+    if (!(aValue instanceof Date)) {
+      return new Date(aValue);
+    }
+    return aValue;
+  }
+  return undefined;
+}
+
 function exportContact(aRecord) {
   if (aRecord) {
     delete aRecord.search;
   }
   return aRecord;
 }
 
 function ContactDispatcher(aContacts, aFullContacts, aCallback, aNewTxn, aClearDispatcher, aFailureCb) {
@@ -579,16 +589,42 @@ ContactDB.prototype = {
               cursor.update(cursor.value);
             }
             cursor.continue();
           } else {
            next();
           }
         };
       },
+      function upgrade15to16() {
+        if (DEBUG) debug("Fix Date properties");
+        if (!objectStore) {
+         objectStore = aTransaction.objectStore(STORE_NAME);
+        }
+        const DATE_PROPERTIES = ["bday", "anniversary"];
+        objectStore.openCursor().onsuccess = function(event) {
+          let cursor = event.target.result;
+          let changed = false;
+          if (cursor) {
+            let props = cursor.value.properties;
+            for (let prop of DATE_PROPERTIES) {
+              if (props[prop] && !(props[prop] instanceof Date)) {
+                cursor.value.properties[prop] = new Date(props[prop]);
+                changed = true;
+              }
+            }
+            if (changed) {
+              cursor.update(cursor.value);
+            }
+            cursor.continue();
+          } else {
+           next();
+          }
+        };
+      },
     ];
 
     let index = aOldVersion;
     let outer = this;
     function next() {
       if (index == aNewVersion) {
         outer.incrementRevision(aTransaction);
         return;
--- a/dom/webidl/Contacts.webidl
+++ b/dom/webidl/Contacts.webidl
@@ -133,17 +133,17 @@ interface mozContact {
            attribute object?      nickname;
            attribute object?      category;
            attribute object?      org;
            attribute object?      jobTitle;
            attribute object?      note;
            attribute object?      key;
 
   [ChromeOnly]
-  void setMetadata(DOMString id, optional Date published, optional Date updated);
+  void setMetadata(DOMString id, Date? published, Date? updated);
 
   jsonifier;
 };
 
 dictionary ContactFindSortOptions {
   DOMString sortBy;                    // "givenName" or "familyName"
   DOMString sortOrder = "ascending";   // e.g. "descending"
 };
--- a/mobile/android/base/ContactService.java
+++ b/mobile/android/base/ContactService.java
@@ -644,18 +644,18 @@ public class ContactService implements G
             putPossibleNullValueInJSONObject("bday", bday, contactProperties);
             putPossibleNullValueInJSONObject("anniversary", anniversary, contactProperties);
             putPossibleNullValueInJSONObject("sex", sex, contactProperties);
             putPossibleNullValueInJSONObject("genderIdentity", genderIdentity, contactProperties);
             putPossibleNullValueInJSONObject("key", key, contactProperties);
 
             // Add the raw contact ID and the properties to the contact
             contact.put("id", String.valueOf(rawContactId));
-            contact.put("updated", "0000T00:00:00.000Z");
-            contact.put("published", "0000T00:00:00.000Z");
+            contact.put("updated", null);
+            contact.put("published", null);
             contact.put("properties", contactProperties);
         } catch (JSONException e) {
             throw new IllegalArgumentException(e);
         }
 
         if (DEBUG) {
             try {
                 Log.d(LOGTAG, "Got contact: " + contact.toString(3));
--- a/mobile/android/modules/ContactService.jsm
+++ b/mobile/android/modules/ContactService.jsm
@@ -59,17 +59,25 @@ let ContactService = {
     delete this._requestMessages[aRequestID];
   },
 
   observe: function(aSubject, aTopic, aData) {
     if (DEBUG) {
       debug("observe: subject: " + aSubject + " topic: " + aTopic + " data: " + aData);
     }
 
-    let message = JSON.parse(aData);
+    let message = JSON.parse(aData, function date_reviver(k, v) {
+      // The Java service sends dates as strings, so convert them to Dates before
+      // sending them back to the child.
+      if (v != null && v != "null" &&
+          ["updated", "published", "anniversary", "bday"].indexOf(k) != -1) {
+        return new Date(v);
+      }
+      return v;
+    });
     let requestID = message.requestID;
 
     // The return message topic is the same as the current topic, but without the "Android:" prefix
     let returnMessageTopic = aTopic.substring(8);
 
     switch (aTopic) {
       case "Android:Contacts:Find:Return:OK":
         this._sendAndDeleteReturnMessage(returnMessageTopic, requestID, {requestID: requestID, contacts: message.contacts});