Bug 793329 - If the trusted UI is closed on device, fire an onerror callback in mozPay indicating as such. r=fabrice, a=blocking-basecamp
authorFernando Jiménez <ferjmoreno@gmail.com>
Tue, 16 Oct 2012 11:28:30 +0200
changeset 113418 16d70275df8f5e1118329e60401f6192560ecd73
parent 113417 cbfef8616b633b460987030a1b6798b1869e769b
child 113419 e9d90b26e252a6aff7455a96d3699e4dbe0690fb
push id2343
push userryanvm@gmail.com
push dateWed, 17 Oct 2012 02:08:48 +0000
treeherdermozilla-aurora@e9d90b26e252 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice, blocking-basecamp
bugs793329
milestone18.0a2
Bug 793329 - If the trusted UI is closed on device, fire an onerror callback in mozPay indicating as such. r=fabrice, a=blocking-basecamp
b2g/chrome/content/payment.js
b2g/components/PaymentGlue.js
dom/payment/Payment.jsm
dom/payment/interfaces/nsIPaymentUIGlue.idl
--- a/b2g/chrome/content/payment.js
+++ b/b2g/chrome/content/payment.js
@@ -61,16 +61,20 @@ function closePaymentFlowDialog(aCallbac
   content.addEventListener("mozContentEvent",
                            function closePaymentFlowReturn(evt) {
     if (evt.detail.id == id && aCallback) {
       aCallback();
     }
 
     content.removeEventListener("mozContentEvent",
                                 closePaymentFlowReturn);
+
+    let glue = Cc["@mozilla.org/payment/ui-glue;1"]
+                 .createInstance(Ci.nsIPaymentUIGlue);
+    glue.cleanup();
   });
 
   browser.shell.sendChromeEvent(detail);
 }
 
 addEventListener("DOMContentLoaded", function(e) {
   content.wrappedJSObject.paymentSuccess = paymentSuccess;
   content.wrappedJSObject.paymentFailed = paymentFailed;
--- a/b2g/components/PaymentGlue.js
+++ b/b2g/components/PaymentGlue.js
@@ -28,20 +28,26 @@ function debug (s) {
 function PaymentUI() {
 }
 
 PaymentUI.prototype = {
 
   confirmPaymentRequest: function confirmPaymentRequest(aRequests,
                                                         aSuccessCb,
                                                         aErrorCb) {
+    let _error = function _error(errorMsg) {
+      if (aErrorCb) {
+        aErrorCb.onresult(errorMsg);
+      }
+    };
+
     let browser = Services.wm.getMostRecentWindow("navigator:browser");
     let content = browser.getContentWindow();
-    if (!content && aErrorCb) {
-      aErrorCb.onresult("NO_CONTENT_WINDOW");
+    if (!content) {
+      _error("NO_CONTENT_WINDOW");
       return;
     }
 
     // The UI should listen for mozChromeEvent 'open-payment-confirmation-dialog'
     // type in order to create and show the payment request confirmation frame
     // embeded within a trusted dialog.
     let id = kOpenPaymentConfirmationEvent + "-" + this.getRandomId();
     let detail = {
@@ -51,82 +57,114 @@ PaymentUI.prototype = {
     };
 
     // Once the user confirm the payment request and makes his choice, we get
     // back to the DOM part to get the appropriate payment flow information
     // based on the selected payment provider.
     content.addEventListener("mozContentEvent", function handleSelection(evt) {
       let msg = evt.detail;
       if (msg.id != id) {
-        debug("mozContentEvent. evt.detail.id != " + id);
-        content.removeEventListener("mozContentEvent", handleSelection);
         return;
       }
 
       if (msg.userSelection && aSuccessCb) {
         aSuccessCb.onresult(msg.userSelection);
-      } else if (msg.errorMsg && aErrorCb) {
-        aErrorCb.onresult(msg.errorMsg);
+      } else if (msg.errorMsg) {
+        _error(msg.errorMsg);
       }
 
       content.removeEventListener("mozContentEvent", handleSelection);
     });
 
     browser.shell.sendChromeEvent(detail);
   },
 
   showPaymentFlow: function showPaymentFlow(aPaymentFlowInfo, aErrorCb) {
     debug("showPaymentFlow. uri " + aPaymentFlowInfo.uri);
+
+    let _error = function _error(errorMsg) {
+      if (aErrorCb) {
+        aErrorCb.onresult(errorMsg);
+      }
+    };
+
     // We ask the UI to browse to the selected payment flow.
     let browser = Services.wm.getMostRecentWindow("navigator:browser");
     let content = browser.getContentWindow();
-    if (!content && aErrorCb) {
-      aErrorCb.onresult("NO_CONTENT_WINDOW");
+    if (!content) {
+      _error("NO_CONTENT_WINDOW");
       return;
     }
 
     let id = kOpenPaymentFlowEvent + "-" + this.getRandomId();
     let detail = {
       type: kOpenPaymentFlowEvent,
       id: id,
       uri: aPaymentFlowInfo.uri,
       method: aPaymentFlowInfo.requestMethod,
       jwt: aPaymentFlowInfo.jwt
     };
 
     // At some point the UI would send the created iframe back so the
     // callbacks for firing DOMRequest events can be loaded on its
     // content.
-    content.addEventListener("mozContentEvent", function loadPaymentShim(evt) {
-      if (evt.detail.id != id || !evt.detail.frame) {
+    content.addEventListener("mozContentEvent", (function loadPaymentShim(evt) {
+      if (evt.detail.id != id) {
         content.removeEventListener("mozContentEvent", loadPaymentShim);
         return;
       }
 
       // Try to load the payment shim file containing the payment callbacks
       // in the content script.
+      if (!evt.detail.frame && !evt.detail.errorMsg) {
+        _error("ERROR_LOADING_PAYMENT_SHIM");
+        return;
+      }
       let frame = evt.detail.frame;
       let frameLoader = frame.QueryInterface(Ci.nsIFrameLoaderOwner)
                         .frameLoader;
       let mm = frameLoader.messageManager;
       try {
         mm.loadFrameScript(kPaymentShimFile, true);
       } catch (e) {
         debug("Error loading " + kPaymentShimFile + " as a frame script: " + e);
-        if (aErrorCb) {
-          aErrorCb.onresult("ERROR_LOADING_PAYMENT_SHIM");
-        }
+        _error("ERROR_LOADING_PAYMENT_SHIM");
       } finally {
         content.removeEventListener("mozContentEvent", loadPaymentShim);
       }
-    });
+    }).bind(this));
+
+    // We also listen for UI notifications about a closed payment flow. The UI
+    // should provide the reason of the closure within the 'errorMsg' parameter
+    this._notifyPayFlowClosed = function _notifyPayFlowClosed (evt) {
+      if (evt.detail.id != id) {
+        return;
+      }
+      if (evt.detail.errorMsg) {
+        _error(evt.detail.errorMsg);
+        content.removeEventListener("mozContentEvent",
+                                    this._notifyPayFlowClosed);
+        return;
+      }
+    };
+    content.addEventListener("mozContentEvent",
+                             this._notifyPayFlowClosed.bind(this));
 
     browser.shell.sendChromeEvent(detail);
   },
 
+  cleanup: function cleanup() {
+    let browser = Services.wm.getMostRecentWindow("navigator:browser");
+    let content = browser.getContentWindow();
+    if (!content) {
+      return;
+    }
+    content.removeEventListener("mozContentEvent", this._notifyPayFlowClosed);
+  },
+
   getRandomId: function getRandomId() {
     return uuidgen.generateUUID().toString();
   },
 
   classID: Components.ID("{8b83eabc-7929-47f4-8b48-4dea8d887e4b}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue])
 }
--- a/dom/payment/Payment.jsm
+++ b/dom/payment/Payment.jsm
@@ -344,17 +344,17 @@ let PaymentManager =  {
 
     let glue = Cc["@mozilla.org/payment/ui-glue;1"]
                .createInstance(Ci.nsIPaymentUIGlue);
     if (!glue) {
       debug("Could not create nsIPaymentUIGlue instance");
       this.paymentFailed("CREATE_PAYMENT_GLUE_FAILED");
       return false;
     }
-    glue.showPaymentFlow(paymentFlowInfo, this.paymentFailed);
+    glue.showPaymentFlow(paymentFlowInfo, this.paymentFailed.bind(this));
   },
 
   // nsIObserver
 
   observe: function observe(subject, topic, data) {
     if (topic == "xpcom-shutdown") {
       for each (let msgname in PAYMENT_IPC_MSG_NAMES) {
         ppmm.removeMessageListener(msgname, this);
--- a/dom/payment/interfaces/nsIPaymentUIGlue.idl
+++ b/dom/payment/interfaces/nsIPaymentUIGlue.idl
@@ -7,20 +7,22 @@
 interface nsIPaymentFlowInfo;
 
 [scriptable, function, uuid(ca475754-6852-49a2-97e8-8a94cc7a453f)]
 interface nsIPaymentUIGlueCallback : nsISupports
 {
     void onresult(in DOMString result);
 };
 
-[scriptable, uuid(c3ff92b3-f24f-4f93-afda-e92a112a80f8)]
+[scriptable, uuid(344e5442-7cc2-4636-bc42-e2249cb67813)]
 interface nsIPaymentUIGlue : nsISupports
 {
     // The 'paymentRequestsInfo' contains the payment request information
-    // for each JWT provided via navigator.mozPay call.    
+    // for each JWT provided via navigator.mozPay call.
     void confirmPaymentRequest(in jsval paymentRequestsInfo,
                                in nsIPaymentUIGlueCallback successCb,
                                in nsIPaymentUIGlueCallback errorCb);
 
     void showPaymentFlow(in nsIPaymentFlowInfo paymentFlowInfo,
                          in nsIPaymentUIGlueCallback errorCb);
+
+    void cleanup();
 };