Bug 896945 - Allow System Messages to inform gaia they should bring up the receiving app in a configurable way. r=fabrice, a=leo+
authorAntonio M. Amaya <amac@tid.es>
Thu, 25 Jul 2013 14:36:15 +0200
changeset 119817 150c3f4ad24b3690cbc76ae462b4ac02d137368b
parent 119816 c4c6d2fe8d52bf8dee3d79c5487f3fe1c837306e
child 119818 44de5fb4e8d0b73c1167945b139fc108fd15cf21
push id1009
push userryanvm@gmail.com
push dateMon, 29 Jul 2013 15:40:20 +0000
reviewersfabrice, leo
bugs896945
milestone18.1
Bug 896945 - Allow System Messages to inform gaia they should bring up the receiving app in a configurable way. r=fabrice, a=leo+
b2g/chrome/content/shell.js
dom/activities/src/ActivityMessageConfigurator.js
dom/messages/SystemMessageInternal.js
dom/messages/interfaces/nsISystemMessagesInternal.idl
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -524,16 +524,18 @@ var shell = {
 
   sendSystemMessage: function shell_sendSystemMessage(msg) {
     let origin = Services.io.newURI(msg.manifest, null, null).prePath;
     this.sendChromeEvent({
       type: 'open-app',
       url: msg.uri,
       manifestURL: msg.manifest,
       isActivity: (msg.type == 'activity'),
+      onlyShowApp: msg.onlyShowApp,
+      showApp: msg.showApp,
       target: msg.target,
       expectingSystemMessage: true
     });
   },
 
   receiveMessage: function shell_receiveMessage(message) {
     var activities = { 'content-handler': { name: 'view', response: null },
                        'dial-handler':    { name: 'dial', response: null },
--- a/dom/activities/src/ActivityMessageConfigurator.js
+++ b/dom/activities/src/ActivityMessageConfigurator.js
@@ -16,18 +16,18 @@ function debug(aMsg) {
 /**
   * nsISystemMessagesConfigurator implementation.
   */
 function ActivityMessageConfigurator() {
   debug("ActivityMessageConfigurator");
 }
 
 ActivityMessageConfigurator.prototype = {
-  get safeToSendBeforeRunningApp() {
-    debug("safeToSendBeforeRunningApp returning false");
-    return false;
+  get mustShowRunningApp() {
+    debug("mustShowRunningApp returning true");
+    return true;
   },
 
   classID: Components.ID("{d2296daa-c406-4c5e-b698-e5f2c1715798}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesConfigurator])
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivityMessageConfigurator]);
--- a/dom/messages/SystemMessageInternal.js
+++ b/dom/messages/SystemMessageInternal.js
@@ -44,18 +44,18 @@ const kMessages =["SystemMessageManager:
                   "child-process-shutdown"]
 
 function debug(aMsg) {
   // dump("-- SystemMessageInternal " + Date.now() + " : " + aMsg + "\n");
 }
 
 
 let defaultMessageConfigurator = {
-  get safeToSendBeforeRunningApp() {
-    return true;
+  get mustShowRunningApp() {
+    return false;
   }
 };
 
 const MSG_SENT_SUCCESS = 0;
 const MSG_SENT_FAILURE_PERM_DENIED = 1;
 const MSG_SENT_FAILURE_APP_NOT_RUNNING = 2;
 
 // Implementation of the component used by internal users.
@@ -197,21 +197,18 @@ SystemMessageInternal.prototype = {
 
       // Queue this message in the corresponding pages.
       this._queueMessage(aPage, aMessage, messageID);
 
       // Open app pages to handle their pending messages.
       // Note that we only need to open each app page once.
       let key = this._createKeyForPage(aPage);
       if (!pagesToOpen.hasOwnProperty(key)) {
-        if (result === MSG_SENT_FAILURE_APP_NOT_RUNNING) {
-          // Don't open the page again if we already sent the message to it.
-          this._openAppPage(aPage, aMessage);
-          pagesToOpen[key] = true;
-        }
+        this._openAppPage(aPage, aMessage, result);
+        pagesToOpen[key] = true;
       }
     }, this);
   },
 
   broadcastMessage: function broadcastMessage(aType, aMessage) {
     // Buffer system messages until the webapps' registration is ready,
     // so that we can know the correct pages registered to be broadcasted.
     if (!this._webappsRegistryReady) {
@@ -245,21 +242,18 @@ SystemMessageInternal.prototype = {
 
         // Queue this message in the corresponding pages.
         this._queueMessage(aPage, aMessage, messageID);
 
         // Open app pages to handle their pending messages.
         // Note that we only need to open each app page once.
         let key = this._createKeyForPage(aPage);
         if (!pagesToOpen.hasOwnProperty(key)) {
-          if (result === MSG_SENT_FAILURE_APP_NOT_RUNNING) {
-            // Open app pages to handle their pending messages.
-            this._openAppPage(aPage, aMessage);
-            pagesToOpen[key] = true;
-          }
+          this._openAppPage(aPage, aMessage, result);
+          pagesToOpen[key] = true;
         }
       }
     }, this);
   },
 
   registerPage: function registerPage(aType, aPageURI, aManifestURI) {
     if (!aPageURI || !aManifestURI) {
       throw Cr.NS_ERROR_INVALID_ARG;
@@ -528,22 +522,37 @@ SystemMessageInternal.prototype = {
     // Queue the message for this page because we've never known if an app is
     // opened or not. We'll clean it up when the app has already received it.
     aPage.pendingMessages.push({ msg: aMessage, msgID: aMessageID });
     if (aPage.pendingMessages.length > kMaxPendingMessages) {
       aPage.pendingMessages.splice(0, 1);
     }
   },
 
-  _openAppPage: function _openAppPage(aPage, aMessage) {
+  _openAppPage: function _openAppPage(aPage, aMessage, aMsgSentStatus) {
+    // This means the app must be brought to the foreground.
+    let showApp = this._getMessageConfigurator(aPage.type).mustShowRunningApp;
+
+    // We should send the open-app message if the system message was
+    // not sent, or if it was sent but we should show the app anyway.
+    if ((aMsgSentStatus === MSG_SENT_SUCCESS) && !showApp) {
+      return;
+    }
+
+    // This flag means the app must *only* be brought to the foreground
+    // and we don't need to load the app to handle messages.
+    let onlyShowApp = (aMsgSentStatus === MSG_SENT_SUCCESS) && showApp;
+
     // We don't need to send the full object to observers.
     let page = { uri: aPage.uri,
                  manifest: aPage.manifest,
                  type: aPage.type,
-                 target: aMessage.target };
+                 target: aMessage.target,
+                 onlyShowApp: onlyShowApp,
+                 showApp: showApp };
     debug("Asking to open " + JSON.stringify(page));
     Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page));
   },
 
   _isPageMatched: function _isPageMatched(aPage, aType, aPageURI, aManifestURI) {
     return (aPage.type === aType &&
             aPage.manifest === aManifestURI &&
             aPage.uri === aPageURI)
@@ -577,50 +586,44 @@ SystemMessageInternal.prototype = {
       return MSG_SENT_FAILURE_PERM_DENIED;
     }
 
     let appPageIsRunning = false;
     let pageKey = this._createKeyForPage({ type: aType,
                                            manifest: aManifestURI,
                                            uri: aPageURI });
 
-    // Tries to send the message to a previously opened app only if it's safe
-    // to do so. Generically, it's safe to send the message if the app isn't
-    // going to be reloaded. And it's not safe otherwise
-    if (this._getMessageConfigurator(aType).safeToSendBeforeRunningApp) {
-
-      let targets = this._listeners[aManifestURI];
-      if (targets) {
-        for (let index = 0; index < targets.length; ++index) {
-          let target = targets[index];
-          // We only need to send the system message to the targets (processes)
-          // which contain the window page that matches the manifest/page URL of
-          // the destination of system message.
-          if (target.winCounts[aPageURI] === undefined) {
-            continue;
-          }
+    let targets = this._listeners[aManifestURI];
+    if (targets) {
+      for (let index = 0; index < targets.length; ++index) {
+        let target = targets[index];
+        // We only need to send the system message to the targets (processes)
+        // which contain the window page that matches the manifest/page URL of
+        // the destination of system message.
+        if (target.winCounts[aPageURI] === undefined) {
+          continue;
+        }
 
-          appPageIsRunning = true;
-          // We need to acquire a CPU wake lock for that page and expect that
-          // we'll receive a "SystemMessageManager:HandleMessagesDone" message
-          // when the page finishes handling the system message. At that point,
-          // we'll release the lock we acquired.
-          this._acquireCpuWakeLock(pageKey);
+        appPageIsRunning = true;
+        // We need to acquire a CPU wake lock for that page and expect that
+        // we'll receive a "SystemMessageManager:HandleMessagesDone" message
+        // when the page finishes handling the system message. At that point,
+        // we'll release the lock we acquired.
+        this._acquireCpuWakeLock(pageKey);
 
-          // Multiple windows can share the same target (process), the content
-          // window needs to check if the manifest/page URL is matched. Only
-          // *one* window should handle the system message.
-          let manager = target.target;
-          manager.sendAsyncMessage("SystemMessageManager:Message",
-                                   { type: aType,
-                                     msg: aMessage,
-                                     manifest: aManifestURI,
-                                     uri: aPageURI,
-                                     msgID: aMessageID });
-        }
+        // Multiple windows can share the same target (process), the content
+        // window needs to check if the manifest/page URL is matched. Only
+        // *one* window should handle the system message.
+        let manager = target.target;
+        manager.sendAsyncMessage("SystemMessageManager:Message",
+                                 { type: aType,
+                                   msg: aMessage,
+                                   manifest: aManifestURI,
+                                   uri: aPageURI,
+                                   msgID: aMessageID });
       }
     }
 
     if (!appPageIsRunning) {
       // The app page isn't running and relies on the 'open-app' chrome event to
       // wake it up. We still need to acquire a CPU wake lock for that page and
       // expect that we will receive a "SystemMessageManager:HandleMessagesDone"
       // message when the page finishes handling the system message with other
--- a/dom/messages/interfaces/nsISystemMessagesInternal.idl
+++ b/dom/messages/interfaces/nsISystemMessagesInternal.idl
@@ -47,18 +47,17 @@ interface nsISystemMessagesWrapper: nsIS
    */
   jsval wrapMessage(in jsval message, in nsIDOMWindow window);
 };
 
 /*
  * Implements an interface to allow specific message types to
  * configure some behaviors
  */
-[scriptable, uuid(8a71981b-a462-4697-b63c-925997f9d47b)]
+[scriptable, uuid(a0e970f6-faa9-4605-89d6-fafae8b10a80)]
 interface nsISystemMessagesConfigurator: nsISupports
 {
   /*
-   * Will be true if this type of system messages is safe to send
-   * before the frontend has activated the app to process it.
-   * The default value (if there's no overriding class) is true
+   * Will be true if this type of system messages assumes/requires
+   * that the app will be brought to the front always.
    */
-  readonly attribute boolean safeToSendBeforeRunningApp;
+  readonly attribute boolean mustShowRunningApp;
 };