Bug 776027 - Allow nsIActivityUIGlueCallback to handle native and web activities. r=fabrice
authorJosh Dover <gerfuls@gmail.com>
Fri, 25 Apr 2014 16:29:00 +0200
changeset 180949 025898d5577cd0eee55ce5c5ec757fd55daccac7
parent 180948 c15e4803607d883069fc9e274bbb399cb6f3e5b5
child 180950 fac267a41e5c011df9f92cbf2688e9bfba2e05bb
push id26687
push usercbook@mozilla.com
push dateWed, 30 Apr 2014 13:02:09 +0000
treeherdermozilla-central@727238c13756 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice
bugs776027
milestone32.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 776027 - Allow nsIActivityUIGlueCallback to handle native and web activities. r=fabrice
b2g/components/ActivitiesGlue.js
dom/activities/interfaces/nsIActivityUIGlue.idl
dom/activities/src/ActivitiesService.jsm
--- a/b2g/components/ActivitiesGlue.js
+++ b/b2g/components/ActivitiesGlue.js
@@ -43,25 +43,32 @@ ActivitiesDialog.prototype = {
 
     // Listen the resulting choice from the front-end. If there is no choice,
     // let's return -1, which means the user has cancelled the dialog.
     SystemAppProxy.addEventListener("mozContentEvent", function act_getChoice(evt) {
       if (evt.detail.id != id)
         return;
 
       SystemAppProxy.removeEventListener("mozContentEvent", act_getChoice);
-      activity.callback.handleEvent(evt.detail.value !== undefined
+      activity.callback.handleEvent(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY,
+                                    evt.detail.value !== undefined
                                       ? evt.detail.value
                                       : -1);
     });
 
     SystemAppProxy.dispatchEvent(detail);
   },
 
   chooseActivity: function ap_chooseActivity(aOptions, aActivities, aCallback) {
+    // B2G does not have an alternate activity system, make no choice and return.
+    if (aActivities.length === 0) {
+      aCallback(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY, -1);
+      return;
+    }
+
     this.activities.push({
       name: aOptions.name,
       list: aActivities,
       callback: aCallback
     });
     Services.tm.currentThread.dispatch(this, Ci.nsIEventTarget.DISPATCH_NORMAL);
   },
 
--- a/dom/activities/interfaces/nsIActivityUIGlue.idl
+++ b/dom/activities/interfaces/nsIActivityUIGlue.idl
@@ -1,25 +1,45 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, function, uuid(7a16feb4-5a78-4589-9174-b728f26942e2)]
+[scriptable, function, uuid(674b6e69-05f0-41da-aabd-4184ea85c9d8)]
 interface nsIActivityUIGlueCallback : nsISupports
 {
-    void handleEvent(in long choice);
+    /**
+     * The activity service should start the activity at the specified index.
+     */
+    const short WEBAPPS_ACTIVITY = 0;
+
+    /**
+     * The activity service should deliver the specified result to the MozActivity callback.
+     */
+    const short NATIVE_ACTIVITY  = 1;
+
+    /**
+      * Called if the user picked an activitiy to launch.
+      * @param resultType Inidcates that {@code result} is an index or a native activity result.
+      * @param result     If WEBAPPS_ACTIVITY, the index of the chosen activity. Send '-1' if no choice is made.
+                          If NATIVE_ACTIVITY, the return value to be sent to the MozActivity.
+      */
+    void handleEvent(in short resultType, in jsval result);
 };
 
 /**
   * To be implemented by @mozilla.org/dom/activities/ui-glue;1
   */
-[scriptable, uuid(03e6743c-2fc3-43fa-bcb3-0476947c8ac5)]
+[scriptable, uuid(3caef69f-3569-4b19-bcea-1cfb0fee4466)]
 interface nsIActivityUIGlue : nsISupports
 {
     /**
+      * This method is called even if the size of {@code activities} is 0 so that the callee can
+      * decide whether or not to defer the request to an alternate activity system.
+      *
       * @param options     The ActivityOptions object in the form of { name: "send", data: { ... } }
       * @param activities  A json blob which is an array of { "title":"...", "icon":"..." }.
-      * @param onresult    The callback to send the index of the choosen activity. Send -1 if no choice is made.
+      * @param callback    The callback to send the index of the choosen activity, or the result.
       */
-    void chooseActivity(in jsval options, in jsval activities, in nsIActivityUIGlueCallback onresult);
+    void chooseActivity(in jsval options, in jsval activities,
+        in nsIActivityUIGlueCallback callback);
 };
--- a/dom/activities/src/ActivitiesService.jsm
+++ b/dom/activities/src/ActivitiesService.jsm
@@ -201,69 +201,83 @@ let Activities = {
     *   activity data as a payload.
     */
   startActivity: function activities_startActivity(aMsg) {
     debug("StartActivity: " + JSON.stringify(aMsg));
 
     let successCb = function successCb(aResults) {
       debug(JSON.stringify(aResults));
 
-      // We have no matching activity registered, let's fire an error.
-      if (aResults.options.length === 0) {
-        Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
-          "id": aMsg.id,
-          "error": "NO_PROVIDER"
-        });
-        delete Activities.callers[aMsg.id];
-        return;
-      }
+      function getActivityChoice(aResultType, aResult) {
+        switch(aResultType) {
+          case Ci.nsIActivityUIGlueCallback.NATIVE_ACTIVITY: {
+            Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
+              "id": aMsg.id,
+              "result": aResult
+            });
+            break;
+          }
+          case Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY: {
+            debug("Activity choice: " + aResult);
 
-      function getActivityChoice(aChoice) {
-        debug("Activity choice: " + aChoice);
+            // We have no matching activity registered, let's fire an error.
+            // Don't do this check until we have passed to UIGlue so the glue can choose to launch
+            // its own activity if needed.
+            if (aResults.options.length === 0) {
+              Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
+                "id": aMsg.id,
+                "error": "NO_PROVIDER"
+              });
+              delete Activities.callers[aMsg.id];
+              return;
+            }
 
-        // The user has cancelled the choice, fire an error.
-        if (aChoice === -1) {
-          Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
-            "id": aMsg.id,
-            "error": "ActivityCanceled"
-          });
-          delete Activities.callers[aMsg.id];
-          return;
-        }
+            // The user has cancelled the choice, fire an error.
+            if (aResult === -1) {
+              Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
+                "id": aMsg.id,
+                "error": "ActivityCanceled"
+              });
+              delete Activities.callers[aMsg.id];
+              return;
+            }
 
-        let sysmm = Cc["@mozilla.org/system-message-internal;1"]
-                      .getService(Ci.nsISystemMessagesInternal);
-        if (!sysmm) {
-          // System message is not present, what should we do?
-          delete Activities.callers[aMsg.id];
-          return;
-        }
+            let sysmm = Cc["@mozilla.org/system-message-internal;1"]
+                          .getService(Ci.nsISystemMessagesInternal);
+            if (!sysmm) {
+              // System message is not present, what should we do?
+              delete Activities.callers[aMsg.id];
+              return;
+            }
 
-        debug("Sending system message...");
-        let result = aResults.options[aChoice];
-        sysmm.sendMessage("activity", {
-            "id": aMsg.id,
-            "payload": aMsg.options,
-            "target": result.description
-          },
-          Services.io.newURI(result.description.href, null, null),
-          Services.io.newURI(result.manifest, null, null),
-          {
-            "manifestURL": Activities.callers[aMsg.id].manifestURL,
-            "pageURL": Activities.callers[aMsg.id].pageURL
-          });
+            debug("Sending system message...");
+            let result = aResults.options[aResult];
+            sysmm.sendMessage("activity", {
+                "id": aMsg.id,
+                "payload": aMsg.options,
+                "target": result.description
+              },
+              Services.io.newURI(result.description.href, null, null),
+              Services.io.newURI(result.manifest, null, null),
+              {
+                "manifestURL": Activities.callers[aMsg.id].manifestURL,
+                "pageURL": Activities.callers[aMsg.id].pageURL
+              });
 
-        if (!result.description.returnValue) {
-          Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
-            "id": aMsg.id,
-            "result": null
-          });
-          // No need to notify observers, since we don't want the caller
-          // to be raised on the foreground that quick.
-          delete Activities.callers[aMsg.id];
+            if (!result.description.returnValue) {
+              Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
+                "id": aMsg.id,
+                "result": null
+              });
+              // No need to notify observers, since we don't want the caller
+              // to be raised on the foreground that quick.
+              delete Activities.callers[aMsg.id];
+            }
+            break;
+          }
         }
       };
 
       let glue = Cc["@mozilla.org/dom/activities/ui-glue;1"]
                    .createInstance(Ci.nsIActivityUIGlue);
       glue.chooseActivity(aMsg.options, aResults.options, getActivityChoice);
     };