Bug 898499 - Support mozPay API on desktop webapprt. r=ferjm
authorMarco Castelluccio <mar.castelluccio@studenti.unina.it>
Fri, 27 Sep 2013 14:38:14 -0400
changeset 163838 44558c02904e66370dc5a5e28d1b395751de3fa1
parent 163837 54a7972a9358a52229ff00eedab8a13f558255dc
child 163839 ca0f0d8b8cd6dec1c822b47052d62b0011dca40f
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersferjm
bugs898499
milestone27.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 898499 - Support mozPay API on desktop webapprt. r=ferjm
b2g/app/b2g.js
browser/confvars.sh
browser/installer/package-manifest.in
dom/payment/Payment.js
mobile/android/app/mobile.js
webapprt/PaymentUIGlue.js
webapprt/Startup.jsm
webapprt/components.manifest
webapprt/locales/en-US/webapprt/webapp.properties
webapprt/moz.build
webapprt/prefs.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -447,16 +447,19 @@ pref("dom.mozPermissionSettings.enabled"
 
 // controls if we want camera support
 pref("device.camera.enabled", true);
 pref("media.realtime_decoder.enabled", true);
 
 // TCPSocket
 pref("dom.mozTCPSocket.enabled", true);
 
+// WebPayment
+pref("dom.mozPay.enabled", true);
+
 // "Preview" landing of bug 710563, which is bogged down in analysis
 // of talos regression.  This is a needed change for higher-framerate
 // CSS animations, and incidentally works around an apparent bug in
 // our handling of requestAnimationFrame() listeners, which are
 // supposed to enable this REPEATING_PRECISE_CAN_SKIP behavior.  The
 // secondary bug isn't really worth investigating since it's obseleted
 // by bug 710563.
 pref("layout.frame_rate.precise", true);
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -53,8 +53,10 @@ MOZ_PROFILE_MIGRATOR=1
 MOZ_EXTENSION_MANAGER=1
 MOZ_APP_STATIC_INI=1
 MOZ_WEBAPP_RUNTIME=1
 MOZ_MEDIA_NAVIGATOR=1
 if test "$OS_TARGET" = "WINNT" -o "$OS_TARGET" = "Darwin"; then
   MOZ_FOLD_LIBS=1
 fi
 MOZ_WEBGL_CONFORMANT=1
+# Enable navigator.mozPay
+MOZ_PAY=1
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -218,16 +218,17 @@
 @BINPATH@/components/dom_webspeechrecognition.xpt
 #endif
 @BINPATH@/components/dom_xbl.xpt
 @BINPATH@/components/dom_xpath.xpt
 @BINPATH@/components/dom_xul.xpt
 #ifdef MOZ_GAMEPAD
 @BINPATH@/components/dom_gamepad.xpt
 #endif
+@BINPATH@/components/dom_payment.xpt
 @BINPATH@/components/downloads.xpt
 @BINPATH@/components/editor.xpt
 @BINPATH@/components/embed_base.xpt
 @BINPATH@/components/extensions.xpt
 @BINPATH@/components/exthandler.xpt
 @BINPATH@/components/exthelper.xpt
 @BINPATH@/components/fastfind.xpt
 @BINPATH@/components/feeds.xpt
@@ -535,16 +536,21 @@
 @BINPATH@/components/TCPSocket.js
 @BINPATH@/components/TCPServerSocket.js
 @BINPATH@/components/TCPSocketParentIntermediary.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
+
 #ifdef MOZ_WEBRTC
 @BINPATH@/components/PeerConnection.js
 @BINPATH@/components/PeerConnection.manifest
 #endif
 
 @BINPATH@/components/HttpDataUsage.manifest
 @BINPATH@/components/HttpDataUsage.js
 
@@ -767,16 +773,17 @@ bin/libfreebl_32int64_3.so
 @BINPATH@/webapprt/chrome.manifest
 @BINPATH@/webapprt/chrome/webapprt@JAREXT@
 @BINPATH@/webapprt/chrome/webapprt.manifest
 @BINPATH@/webapprt/chrome/@AB_CD@@JAREXT@
 @BINPATH@/webapprt/chrome/@AB_CD@.manifest
 @BINPATH@/webapprt/components/CommandLineHandler.js
 @BINPATH@/webapprt/components/ContentPermission.js
 @BINPATH@/webapprt/components/DirectoryProvider.js
+@BINPATH@/webapprt/components/PaymentUIGlue.js
 @BINPATH@/webapprt/components/components.manifest
 @BINPATH@/webapprt/defaults/preferences/prefs.js
 @BINPATH@/webapprt/modules/Startup.jsm
 @BINPATH@/webapprt/modules/WebappRT.jsm
 @BINPATH@/webapprt/modules/WebappsHandler.jsm
 @BINPATH@/webapprt/modules/RemoteDebugger.jsm
 #endif
 
--- a/dom/payment/Payment.js
+++ b/dom/payment/Payment.js
@@ -73,16 +73,24 @@ PaymentContentHelper.prototype = {
       requestId: requestId
     });
     return request;
   },
 
   // nsIDOMGlobalPropertyInitializer
 
   init: function(aWindow) {
+    try {
+      if (!Services.prefs.getBoolPref("dom.mozPay.enabled")) {
+        return null;
+      }
+    } catch (e) {
+      return null;
+    }
+
     this._window = aWindow;
     this.initDOMRequestHelper(aWindow, PAYMENT_IPC_MSG_NAMES);
 
     try {
       this._debug =
         Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
         && Services.prefs.getBoolPref(PREF_DEBUG);
     } catch(e) {
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -745,16 +745,19 @@ pref("browser.contentHandlers.types.1.ur
 pref("browser.contentHandlers.types.1.type", "application/vnd.mozilla.maybe.feed");
 pref("browser.contentHandlers.types.2.title", "chrome://browser/locale/region.properties");
 pref("browser.contentHandlers.types.2.uri", "chrome://browser/locale/region.properties");
 pref("browser.contentHandlers.types.2.type", "application/vnd.mozilla.maybe.feed");
 pref("browser.contentHandlers.types.3.title", "chrome://browser/locale/region.properties");
 pref("browser.contentHandlers.types.3.uri", "chrome://browser/locale/region.properties");
 pref("browser.contentHandlers.types.3.type", "application/vnd.mozilla.maybe.feed");
 
+// WebPayment
+pref("dom.mozPay.enabled", true);
+
 #ifndef RELEASE_BUILD
 pref("dom.payment.provider.0.name", "Firefox Marketplace");
 pref("dom.payment.provider.0.description", "marketplace.firefox.com");
 pref("dom.payment.provider.0.uri", "https://marketplace.firefox.com/mozpay/?req=");
 pref("dom.payment.provider.0.type", "mozilla/payments/pay/v1");
 pref("dom.payment.provider.0.requestMethod", "GET");
 #endif
 
new file mode 100644
--- /dev/null
+++ b/webapprt/PaymentUIGlue.js
@@ -0,0 +1,140 @@
+/* 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 { interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
+                                  "@mozilla.org/childprocessmessagemanager;1",
+                                  "nsIMessageSender");
+
+function paymentSuccess(aRequestId) {
+  return paymentCallback(aRequestId, "Payment:Success");
+}
+
+function paymentFailed(aRequestId) {
+  return paymentCallback(aRequestId, "Payment:Failed");
+}
+
+function paymentCallback(aRequestId, aMsg) {
+  return function(aResult) {
+          closePaymentWindow(aRequestId, function() {
+            cpmm.sendAsyncMessage(aMsg, { result: aResult,
+                                          requestId: aRequestId });
+          });
+        };
+}
+
+let payments = {};
+
+function closePaymentWindow(aId, aCallback) {
+  if (payments[aId]) {
+    payments[aId].handled = true;
+    payments[aId].win.close();
+    payments[aId] = null;
+  }
+
+  aCallback();
+}
+
+function PaymentUI() {}
+
+PaymentUI.prototype = {
+  classID: Components.ID("{ede1124f-72e8-4a31-9567-3270d46f21fb}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue]),
+
+  confirmPaymentRequest: function(aRequestId, aRequests, aSuccessCb, aErrorCb) {
+    // If there's only one payment provider that will work, just move on
+    // without prompting the user.
+    if (aRequests.length == 1) {
+      aSuccessCb.onresult(aRequestId, aRequests[0].wrappedJSObject.type);
+      return;
+    }
+
+    let items = [];
+
+    // Otherwise, let the user select a payment provider from a list.
+    for (let i = 0; i < aRequests.length; i++) {
+      let request = aRequests[i].wrappedJSObject;
+      let requestText = request.providerName;
+      if (request.productPrice && Array.isArray(request.productPrice)) {
+        // We should guess the user currency and use that instead.
+        requestText += " (" + request.productPrice[0].amount + " " +
+                              request.productPrice[0].currency + ")";
+      }
+      items.push(requestText);
+    }
+
+    let selected = {};
+
+    let bundle = Services.strings.
+                   createBundle("chrome://webapprt/locale/webapp.properties");
+    let result = Services.prompt.
+                   select(null, bundle.GetStringFromName("paymentDialog.title"),
+                          bundle.GetStringFromName("paymentDialog.message"),
+                          items.length, items, selected);
+    if (result) {
+      aSuccessCb.onresult(aRequestId,
+                          aRequests[selected.value].wrappedJSObject.type);
+    } else {
+      aErrorCb.onresult(aRequestId, "USER_CANCELLED");
+    }
+  },
+
+  showPaymentFlow: function(aRequestId, aPaymentFlowInfo, aErrorCb) {
+    let win = Services.ww.
+                openWindow(null,
+                           "chrome://webapprt/content/webapp.xul",
+                           "_blank",
+                           "chrome,dialog=no,resizable,scrollbars,centerscreen",
+                           null);
+
+    // Store a reference to the window so that we can close it when the payment
+    // succeeds or fails.
+    payments[aRequestId] = { win: win, handled: false };
+
+    // Inject paymentSuccess and paymentFailed methods into the document after
+    // its loaded.
+    win.addEventListener("DOMWindowCreated", function() {
+      let browserElement = win.document.getElementById("content");
+      browserElement.
+        setAttribute("src", aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt);
+
+      browserElement.addEventListener("DOMWindowCreated", function() {
+        win.document.getElementById("content").contentDocument.defaultView
+           .wrappedJSObject.mozPaymentProvider = {
+             __exposedProps__: {
+               paymentSuccess: 'r',
+               paymentFailed: 'r'
+             },
+             paymentSuccess: paymentSuccess(aRequestId),
+             paymentFailed: paymentFailed(aRequestId)
+           };
+      }, true);
+    });
+
+    let winObserver = function(aClosedWin, aTopic) {
+      if (aTopic == "domwindowclosed") {
+        // Fail the payment if the window is closed.
+        if (aClosedWin == win) {
+          Services.ww.unregisterNotification(winObserver);
+          if (!payments[aRequestId].handled) {
+            aErrorCb.onresult(aRequestId, "USER_CANCELLED");
+          }
+        }
+      }
+    }
+
+    Services.ww.registerNotification(winObserver);
+  },
+
+  cleanup: function() {
+  },
+}
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentUI]);
--- a/webapprt/Startup.jsm
+++ b/webapprt/Startup.jsm
@@ -12,16 +12,17 @@ this.EXPORTED_SYMBOLS = ["startup"];
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 // Initialize DOMApplicationRegistry by importing Webapps.jsm.
 Cu.import("resource://gre/modules/Webapps.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
+Cu.import('resource://gre/modules/Payment.jsm');
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 // Initialize window-independent handling of webapps- notifications.
 Cu.import("resource://webapprt/modules/WebappsHandler.jsm");
 Cu.import("resource://webapprt/modules/WebappRT.jsm");
 
 function isFirstRunOrUpdate() {
--- a/webapprt/components.manifest
+++ b/webapprt/components.manifest
@@ -6,8 +6,12 @@ category command-line-handler x-default 
 # ContentPermission.js
 component {07ef5b2e-88fb-47bd-8cec-d3b0bef11ac4} ContentPermission.js
 contract @mozilla.org/content-permission/prompt;1 {07ef5b2e-88fb-47bd-8cec-d3b0bef11ac4}
 
 # DirectoryProvider.js
 component {e1799fda-4b2f-4457-b671-e0641d95698d} DirectoryProvider.js
 contract @mozilla.org/webapprt/directory-provider;1 {e1799fda-4b2f-4457-b671-e0641d95698d}
 category xpcom-directory-providers webapprt-directory-provider @mozilla.org/webapprt/directory-provider;1
+
+# PaymentUIGlue.js
+component {ede1124f-72e8-4a31-9567-3270d46f21fb} PaymentUIGlue.js
+contract @mozilla.org/payment/ui-glue;1 {ede1124f-72e8-4a31-9567-3270d46f21fb}
--- a/webapprt/locales/en-US/webapprt/webapp.properties
+++ b/webapprt/locales/en-US/webapprt/webapp.properties
@@ -35,8 +35,11 @@ desktop-notification.remember=Remember m
 # LOCALIZATION NOTE (webapps.install.title): %S will be replaced with the name
 # of the webapp being installed.
 webapps.install.title=Install %S
 # LOCALIZATION NOTE (webapps.install.description): %S will be replaced with the
 # name of the webapp being installed.
 webapps.install.description=Do you want to install %S?
 webapps.install.install=Install App
 webapps.install.dontinstall=Don't Install
+
+paymentDialog.title=Payment
+paymentDialog.message=Which payment provider do you want to use?
--- a/webapprt/moz.build
+++ b/webapprt/moz.build
@@ -13,16 +13,17 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gt
 
 DIRS += ['locales']
 TEST_DIRS += ['test']
 
 EXTRA_COMPONENTS += [
     'CommandLineHandler.js',
     'ContentPermission.js',
     'DirectoryProvider.js',
+    'PaymentUIGlue.js',
     'components.manifest',
 ]
 
 EXTRA_JS_MODULES += [
     'RemoteDebugger.jsm',
     'Startup.jsm',
     'WebappRT.jsm',
     'WebappsHandler.jsm',
--- a/webapprt/prefs.js
+++ b/webapprt/prefs.js
@@ -41,16 +41,28 @@ pref("browser.cache.offline.enable", tru
 pref("offline-apps.allow_by_default", true);
 
 // TCPSocket
 pref("dom.mozTCPSocket.enabled", true);
 
 // Enable smooth scrolling
 pref("general.smoothScroll", true);
 
+// WebPayment
+pref("dom.mozPay.enabled", true);
+
+#ifndef RELEASE_BUILD
+// Enable mozPay default provider
+pref("dom.payment.provider.0.name", "Firefox Marketplace");
+pref("dom.payment.provider.0.description", "marketplace.firefox.com");
+pref("dom.payment.provider.0.uri", "https://marketplace.firefox.com/mozpay/?req=");
+pref("dom.payment.provider.0.type", "mozilla/payments/pay/v1");
+pref("dom.payment.provider.0.requestMethod", "GET");
+#endif
+
 // Enable window resize and move
 pref("dom.always_allow_move_resize_window", true);
 
 pref("plugin.allowed_types", "application/x-shockwave-flash,application/futuresplash");
 
 pref("devtools.debugger.remote-enabled", true);
 pref("devtools.debugger.force-local", true);