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 180906 025898d5577cd0eee55ce5c5ec757fd55daccac7
parent 180905 c15e4803607d883069fc9e274bbb399cb6f3e5b5
child 180907 fac267a41e5c011df9f92cbf2688e9bfba2e05bb
push id6576
push usercbook@mozilla.com
push dateWed, 30 Apr 2014 06:53:24 +0000
treeherderfx-team@8d7327159983 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice
bugs776027
milestone32.0a1
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);
     };