Backed out changeset cc0306c09d59 (bug 914888) for frequent xpcshell failures. a...
[gecko.git] / mobile / android / components / PaymentsUI.js
blob902b232b7fbcaa2905e7931bc7e3b88293e2a85d
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
9 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
10 Cu.import("resource://gre/modules/Services.jsm");
12 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
13                                    "@mozilla.org/childprocessmessagemanager;1",
14                                    "nsIMessageSender");
16 function paymentSuccess(aRequestId) {
17   return paymentCallback(aRequestId, "Payment:Success");
20 function paymentFailed(aRequestId) {
21   return paymentCallback(aRequestId, "Payment:Failed");
24 function paymentCallback(aRequestId, aMsg) {
25   return function(aResult) {
26     closePaymentTab(aRequestId, function() {
27       cpmm.sendAsyncMessage(aMsg, { result: aResult,
28                                     requestId: aRequestId });
29     });
30   }
33 let paymentTabs = {};
35 function closePaymentTab(aId, aCallback) {
36   if (paymentTabs[aId]) {
37     // We ask the UI to close the selected payment flow.
38     let content = Services.wm.getMostRecentWindow("navigator:browser");
39     if (content) {
40       content.BrowserApp.closeTab(paymentTabs[aId]);
41     }
43     paymentTabs[aId] = null;
44   }
46   aCallback();
49 function PaymentUI() {
52 PaymentUI.prototype = {
53   get bundle() {
54     delete this.bundle;
55     return this.bundle = Services.strings.createBundle("chrome://browser/locale/payments.properties");
56   },
58   sendMessageToJava: function(aMsg) {
59     let data = Services.androidBridge.handleGeckoMessage(JSON.stringify(aMsg));
60     return JSON.parse(data);
61   },
63   confirmPaymentRequest: function confirmPaymentRequest(aRequestId,
64                                                         aRequests,
65                                                         aSuccessCb,
66                                                         aErrorCb) {
67     let _error = this._error(aErrorCb);
69     let listItems = [];
71     // If there's only one payment provider that will work, just move on without prompting the user.
72     if (aRequests.length == 1) {
73       aSuccessCb.onresult(aRequestId, aRequests[0].wrappedJSObject.type);
74       return;
75     }
77     // Otherwise, let the user select a payment provider from a list.
78     for (let i = 0; i < aRequests.length; i++) {
79       let request = aRequests[i].wrappedJSObject;
80       let requestText = request.providerName;
81       if (request.productPrice) {
82         requestText += " (" + request.productPrice[0].amount + " " +
83                               request.productPrice[0].currency + ")";
84       }
85       listItems.push({ label: requestText });
86     }
88     let p = new Prompt({
89       window: null,
90       title: this.bundle.GetStringFromName("payments.providerdialog.title"),
91     }).setSingleChoiceItems(listItems).show(function(data) {
92       if (data.button > -1 && aSuccessCb) {
93         aSuccessCb.onresult(aRequestId, aRequests[data.button].wrappedJSObject.type);
94       } else {
95         _error(aRequestId, "USER_CANCELED");
96       }
97     });
98   },
100   _error: function(aCallback) {
101     return function _error(id, msg) {
102       if (aCallback) {
103         aCallback.onresult(id, msg);
104       }
105     };
106   },
108   showPaymentFlow: function showPaymentFlow(aRequestId,
109                                             aPaymentFlowInfo,
110                                             aErrorCb) {
111     let _error = this._error(aErrorCb);
113     // We ask the UI to browse to the selected payment flow.
114     let content = Services.wm.getMostRecentWindow("navigator:browser");
115     if (!content) {
116       _error(aRequestId, "NO_CONTENT_WINDOW");
117       return;
118     }
120     // TODO: For now, known payment providers (BlueVia and Mozilla Market)
121     // only accepts the JWT by GET, so we just add it to the URI.
122     // https://github.com/mozilla-b2g/gaia/blob/master/apps/system/js/payment.js
123     let tab = content.BrowserApp.addTab(aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt);
125     // Inject paymentSuccess and paymentFailed methods into the document after its loaded.
126     tab.browser.addEventListener("DOMContentLoaded", function loadPaymentShim() {
127       let frame = tab.browser.contentDocument.defaultView;
128       try {
129         frame.wrappedJSObject.paymentSuccess = paymentSuccess(aRequestId);
130         frame.wrappedJSObject.paymentFailed = paymentFailed(aRequestId);
131       } catch (e) {
132         _error(aRequestId, "ERROR_ADDING_METHODS");
133       } finally {
134         tab.browser.removeEventListener("DOMContentLoaded", loadPaymentShim);
135       }
136     }, false);
138     // fail the payment if the tab is closed on its own
139     tab.browser.addEventListener("TabClose", function paymentCanceled() {
140       paymentFailed(aRequestId)();
141     });
143     // Store a reference to the tab so that we can close it when the payment succeeds or fails.
144     paymentTabs[aRequestId] = tab;
145   },
147   cleanup: function cleanup() {
148     // Nothing to do here.
149   },
151   classID: Components.ID("{3c6c9575-f57e-427b-a8aa-57bc3cbff48f}"), 
152   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue])
155 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentUI]);