Bug 767818 - Implement navigator.pay. Part 4 - B2G implementation; r=fabrice
authorFernando Jiménez <ferjmoreno@gmail.com>
Wed, 29 Aug 2012 18:41:35 -0300
changeset 110132 1fce6214c374be0d7e8096236fc4b327ef0f9063
parent 110131 d0bd9c03e21ba456e839ea896389d47389194a36
child 110133 15f7b4bfd69956f637977e3630640e2d9a8d849c
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice
bugs767818
milestone18.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 767818 - Implement navigator.pay. Part 4 - B2G implementation; r=fabrice
b2g/chrome/content/payment.js
b2g/chrome/content/shell.js
b2g/chrome/jar.mn
b2g/components/B2GComponents.manifest
b2g/components/Makefile.in
b2g/components/PaymentGlue.js
b2g/confvars.sh
b2g/installer/package-manifest.in
new file mode 100644
--- /dev/null
+++ b/b2g/chrome/content/payment.js
@@ -0,0 +1,77 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* 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/. */
+
+// This JS shim contains the callbacks to fire DOMRequest events for
+// navigator.pay API within the payment processor's scope.
+
+"use strict";
+
+dump("======================= payment.js ======================= \n");
+
+let { classes: Cc, interfaces: Ci, utils: Cu }  = Components;
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
+                                   "@mozilla.org/childprocessmessagemanager;1",
+                                   "nsIMessageSender");
+
+XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
+                                   "@mozilla.org/uuid-generator;1",
+                                   "nsIUUIDGenerator");
+
+const kClosePaymentFlowEvent = "close-payment-flow-dialog";
+
+function paymentSuccess(aResult) {
+  closePaymentFlowDialog(function notifySuccess() {
+    cpmm.sendAsyncMessage("Payment:Success", { result: aResult });
+  });
+}
+
+function paymentFailed(aErrorMsg) {
+  closePaymentFlowDialog(function notifyError() {
+    cpmm.sendAsyncMessage("Payment:Failed", { errorMsg: aErrorMsg });
+  });
+}
+
+function closePaymentFlowDialog(aCallback) {
+  // After receiving the payment provider confirmation about the
+  // successful or failed payment flow, we notify the UI to close the
+  // payment flow dialog and return to the caller application.
+  let randomId = uuidgen.generateUUID().toString();
+  let id = kClosePaymentFlowEvent + "-" + randomId;
+
+  let browser = Services.wm.getMostRecentWindow("navigator:browser");
+  let content = browser.getContentWindow();
+  if (!content) {
+    return;
+  }
+
+  let detail = {
+    type: kClosePaymentFlowEvent,
+    id: id
+  };
+
+  // In order to avoid race conditions, we wait for the UI to notify that
+  // it has successfully closed the payment flow and has recovered the
+  // caller app, before notifying the parent process to fire the success
+  // or error event over the DOMRequest.
+  content.addEventListener("mozContentEvent",
+                           function closePaymentFlowReturn(evt) {
+    if (evt.detail.id == id && aCallback) {
+      aCallback();
+    }
+
+    content.removeEventListener("mozContentEvent",
+                                closePaymentFlowReturn);
+  });
+
+  browser.shell.sendChromeEvent(detail);
+}
+
+addEventListener("DOMContentLoaded", function(e) {
+  content.wrappedJSObject.paymentSuccess = paymentSuccess;
+  content.wrappedJSObject.paymentFailed = paymentFailed;
+});
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -13,17 +13,18 @@ Cu.import('resource://gre/modules/XPCOMU
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/ContactService.jsm');
 Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm');
 Cu.import('resource://gre/modules/Webapps.jsm');
 Cu.import('resource://gre/modules/AlarmService.jsm');
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
 Cu.import('resource://gre/modules/ObjectWrapper.jsm');
-Cu.import("resource://gre/modules/accessibility/AccessFu.jsm");
+Cu.import('resource://gre/modules/accessibility/AccessFu.jsm');
+Cu.import('resource://gre/modules/Payment.jsm');
 
 XPCOMUtils.defineLazyServiceGetter(Services, 'env',
                                    '@mozilla.org/process/environment;1',
                                    'nsIEnvironment');
 
 XPCOMUtils.defineLazyServiceGetter(Services, 'ss',
                                    '@mozilla.org/content/style-sheet-service;1',
                                    'nsIStyleSheetService');
--- a/b2g/chrome/jar.mn
+++ b/b2g/chrome/jar.mn
@@ -16,16 +16,18 @@ chrome.jar:
 * content/shell.js                      (content/shell.js)
 #ifndef ANDROID
   content/screen.js                     (content/screen.js)
   content/runapp.js                     (content/runapp.js)
 #endif
   content/content.css                   (content/content.css)
   content/touchcontrols.css             (content/touchcontrols.css)
 
+  content/payment.js                    (content/payment.js)
+
 % override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
 % override chrome://global/skin/netError.css chrome://browser/content/netError.css
 % override chrome://global/skin/media/videocontrols.css chrome://browser/content/touchcontrols.css
 
   content/netError.xhtml                (content/netError.xhtml)
   content/netError.css                  (content/netError.css)
   content/images/errorpage-larry-black.png (content/images/errorpage-larry-black.png)
   content/images/errorpage-larry-white.png (content/images/errorpage-larry-white.png)
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -38,8 +38,11 @@ contract @mozilla.org/dom/activities/ui-
 component {1a94c87a-5ece-4d11-91e1-d29c29f21b28} ProcessGlobal.js
 contract @mozilla.org/b2g-process-global;1 {1a94c87a-5ece-4d11-91e1-d29c29f21b28}
 category app-startup ProcessGlobal service,@mozilla.org/b2g-process-global;1
 
 # ContentHandler.js
 component {d18d0216-d50c-11e1-ba54-efb18d0ef0ac} ContentHandler.js
 contract @mozilla.org/uriloader/content-handler;1?type=application/pdf {d18d0216-d50c-11e1-ba54-efb18d0ef0ac}
 
+# PaymentGlue.js
+component {8b83eabc-7929-47f4-8b48-4dea8d887e4b} PaymentGlue.js
+contract @mozilla.org/payment/ui-glue;1 {8b83eabc-7929-47f4-8b48-4dea8d887e4b}
--- a/b2g/components/Makefile.in
+++ b/b2g/components/Makefile.in
@@ -21,15 +21,16 @@ EXTRA_PP_COMPONENTS = \
         AlertsService.js \
         B2GComponents.manifest \
         CameraContent.js \
         ContentHandler.js \
         ContentPermissionPrompt.js \
         DirectoryProvider.js \
         MozKeyboard.js \
         ProcessGlobal.js \
+        PaymentGlue.js \
         $(NULL)
 
 ifdef MOZ_UPDATER
 EXTRA_PP_COMPONENTS += UpdatePrompt.js
 endif
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/b2g/components/PaymentGlue.js
@@ -0,0 +1,134 @@
+/* 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/. */
+
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+// JS shim that contains the callback functions to be triggered from the
+// payment provider's code in order to fire DOMRequest events.
+const kPaymentShimFile = "chrome://browser/content/payment.js";
+
+// Type of MozChromEvents to handle payment dialogs.
+const kOpenPaymentConfirmationEvent = "open-payment-confirmation-dialog";
+const kOpenPaymentFlowEvent = "open-payment-flow-dialog";
+
+XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
+                                   "@mozilla.org/uuid-generator;1",
+                                   "nsIUUIDGenerator");
+
+function debug (s) {
+  //dump("-*- PaymentGlue: " + s + "\n");
+};
+
+function PaymentUI() {
+}
+
+PaymentUI.prototype = {
+
+  confirmPaymentRequest: function confirmPaymentRequest(aRequests,
+                                                        aSuccessCb,
+                                                        aErrorCb) {
+    let browser = Services.wm.getMostRecentWindow("navigator:browser");
+    let content = browser.getContentWindow();
+    if (!content && aErrorCb) {
+      aErrorCb.onresult("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 = {
+      type: kOpenPaymentConfirmationEvent,
+      id: id,
+      paymentRequests: aRequests
+    };
+
+    // 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);
+      }
+
+      content.removeEventListener("mozContentEvent", handleSelection);
+    });
+
+    browser.shell.sendChromeEvent(detail);
+  },
+
+  showPaymentFlow: function showPaymentFlow(aPaymentFlowInfo, aErrorCb) {
+    debug("showPaymentFlow. uri " + aPaymentFlowInfo.uri);
+    // 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");
+      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.removeEventListener("mozContentEvent", loadPaymentShim);
+        return;
+      }
+
+      // Try to load the payment shim file containing the payment callbacks
+      // in the content script.
+      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");
+        }
+      } finally {
+        content.removeEventListener("mozContentEvent", loadPaymentShim);
+      }
+    });
+
+    browser.shell.sendChromeEvent(detail);
+  },
+
+  getRandomId: function getRandomId() {
+    return uuidgen.generateUUID().toString();
+  },
+
+  classID: Components.ID("{8b83eabc-7929-47f4-8b48-4dea8d887e4b}"),
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue])
+}
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentUI]);
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -33,9 +33,11 @@ else
 MOZ_XULRUNNER=
 MOZ_PLACES=1
 fi
 
 MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
 MOZ_EXTENSION_MANAGER=1
 
 MOZ_SYS_MSG=1
+
+MOZ_PAY=1
 MOZ_TOOLKIT_SEARCH=
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -177,16 +177,17 @@
 @BINPATH@/components/dom_file.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_media.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
 @BINPATH@/components/dom_offline.xpt
+@BINPATH@/components/dom_payment.xpt
 @BINPATH@/components/dom_json.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_mms.xpt
 #endif
 @BINPATH@/components/dom_browserelement.xpt
 @BINPATH@/components/dom_messages.xpt
 @BINPATH@/components/dom_power.xpt
 @BINPATH@/components/dom_range.xpt
@@ -484,16 +485,21 @@
 @BINPATH@/components/ActivityWrapper.js
 
 @BINPATH@/components/TCPSocket.js
 @BINPATH@/components/TCPSocket.manifest
 
 @BINPATH@/components/AppProtocolHandler.js
 @BINPATH@/components/AppProtocolHandler.manifest
 
+@BINPATH@/components/Payment.js
+@BINPATH@/components/PaymentFlowInfo.js
+@BINPATH@/components/PaymentRequestInfo.js
+@BINPATH@/components/Payment.manifest
+
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
 @BINPATH@/components/nsURLClassifier.manifest
 @BINPATH@/components/nsUrlClassifierHashCompleter.js
 @BINPATH@/components/nsUrlClassifierListManager.js
 @BINPATH@/components/nsUrlClassifierLib.js
@@ -685,12 +691,13 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 #ifdef MOZ_UPDATER
 @BINPATH@/components/UpdatePrompt.js
 #endif
 @BINPATH@/components/MozKeyboard.js
 @BINPATH@/components/DirectoryProvider.js
 @BINPATH@/components/ActivitiesGlue.js
 @BINPATH@/components/ProcessGlobal.js
 @BINPATH@/components/ContentHandler.js
+@BINPATH@/components/PaymentGlue.js
 
 #ifdef XP_MACOSX
 @BINPATH@/@DLL_PREFIX@plugin_child_interpose@DLL_SUFFIX@
 #endif