зеркало из https://github.com/mozilla/gecko-dev.git
307 строки
9.2 KiB
JavaScript
307 строки
9.2 KiB
JavaScript
/* 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, results: Cr} = Components;
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
|
"@mozilla.org/childprocessmessagemanager;1",
|
|
"nsIMessageSender");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
|
"@mozilla.org/uuid-generator;1",
|
|
"nsIUUIDGenerator");
|
|
|
|
|
|
const PREF_DEBUG = "dom.payment.debug";
|
|
|
|
var _debug;
|
|
try {
|
|
_debug = Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
|
|
&& Services.prefs.getBoolPref(PREF_DEBUG);
|
|
} catch(e) {
|
|
_debug = false;
|
|
}
|
|
|
|
function DEBUG(s) {
|
|
if (!_debug) {
|
|
return;
|
|
}
|
|
dump("== Payment Provider == " + s + "\n");
|
|
}
|
|
|
|
function DEBUG_E(s) {
|
|
dump("== Payment Provider ERROR == " + s + "\n");
|
|
}
|
|
|
|
const kPaymentFlowCancelled = "payment-flow-cancelled";
|
|
|
|
function PaymentProvider() {
|
|
}
|
|
|
|
PaymentProvider.prototype = {
|
|
init: function(aWindow) {
|
|
let docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIWebNavigation)
|
|
.QueryInterface(Ci.nsIDocShell);
|
|
this._requestId = docshell.paymentRequestId;
|
|
this._oncancelObserver = this.oncancel.bind(this);
|
|
Services.obs.addObserver(this._oncancelObserver,
|
|
kPaymentFlowCancelled,
|
|
false);
|
|
this._strategy = Cc["@mozilla.org/payment/provider-strategy;1"]
|
|
.createInstance(Ci.nsIPaymentProviderStrategy);
|
|
this._window = aWindow;
|
|
},
|
|
|
|
paymentSuccess: function(aResult) {
|
|
_debug && DEBUG("paymentSuccess " + aResult);
|
|
let glue = Cc["@mozilla.org/payment/ui-glue;1"]
|
|
.createInstance(Ci.nsIPaymentUIGlue);
|
|
glue.closePaymentFlow(this._requestId).then(() => {
|
|
if (!this._requestId) {
|
|
return;
|
|
}
|
|
cpmm.sendAsyncMessage("Payment:Success", { result: aResult,
|
|
requestId: this._requestId });
|
|
});
|
|
},
|
|
|
|
paymentFailed: function(aError) {
|
|
_debug && DEBUG("paymentFailed " + aError);
|
|
let glue = Cc["@mozilla.org/payment/ui-glue;1"]
|
|
.createInstance(Ci.nsIPaymentUIGlue);
|
|
glue.closePaymentFlow(this._requestId).then(() => {
|
|
if (!this._requestId) {
|
|
return;
|
|
}
|
|
cpmm.sendAsyncMessage("Payment:Failed", { errorMsg: aError,
|
|
requestId: this._requestId });
|
|
});
|
|
|
|
},
|
|
|
|
get paymentServiceId() {
|
|
return this._strategy.paymentServiceId;
|
|
},
|
|
|
|
set paymentServiceId(aServiceId) {
|
|
this._strategy.paymentServiceId = aServiceId;
|
|
},
|
|
|
|
/**
|
|
* We expose to the payment provider the information of all the SIMs
|
|
* available in the device. iccInfo is an object of this form:
|
|
* {
|
|
* "serviceId1": {
|
|
* mcc: <string>,
|
|
* mnc: <string>,
|
|
* iccId: <string>,
|
|
* dataPrimary: <boolean>
|
|
* },
|
|
* "serviceIdN": {...}
|
|
* }
|
|
*/
|
|
get iccInfo() {
|
|
return this._strategy.iccInfo;
|
|
},
|
|
|
|
oncancel: function() {
|
|
_debug && DEBUG("Cleaning up!");
|
|
|
|
this._strategy.cleanup();
|
|
Services.obs.removeObserver(this._oncancelObserver, kPaymentFlowCancelled);
|
|
if (this._cleanup) {
|
|
this._cleanup();
|
|
}
|
|
},
|
|
|
|
classID: Components.ID("{82144756-72ab-45b7-8621-f3dad431dd2f}"),
|
|
|
|
contractID: "@mozilla.org/payment/provider;1",
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
|
Ci.nsIObserver,
|
|
Ci.nsIDOMGlobalPropertyInitializer])
|
|
};
|
|
|
|
#if defined(MOZ_B2G_RIL) || defined(MOZ_WIDGET_ANDROID)
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "smsService",
|
|
"@mozilla.org/sms/smsservice;1",
|
|
"nsISmsService");
|
|
|
|
const kSilentSmsReceivedTopic = "silent-sms-received";
|
|
|
|
// In order to send messages through nsISmsService, we need to implement
|
|
// nsIMobileMessageCallback, as the WebSMS API implementation is not usable
|
|
// from JS.
|
|
function SilentSmsRequest(aDOMRequest) {
|
|
this.request = aDOMRequest;
|
|
}
|
|
|
|
SilentSmsRequest.prototype = {
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileMessageCallback]),
|
|
|
|
classID: Components.ID("{1d58889c-5660-4cca-a8fd-97ef63e5d3b2}"),
|
|
|
|
notifyMessageSent: function notifyMessageSent(aMessage) {
|
|
_debug && DEBUG("Silent message successfully sent");
|
|
Services.DOMRequest.fireSuccessAsync(this.request, aMessage);
|
|
},
|
|
|
|
notifySendMessageFailed: function notifySendMessageFailed(aError) {
|
|
DEBUG_E("Error sending silent message " + aError);
|
|
Services.DOMRequest.fireErrorAsync(this.request, aError);
|
|
}
|
|
};
|
|
|
|
PaymentProvider.prototype._silentNumbers = null;
|
|
|
|
PaymentProvider.prototype._silentSmsObservers = null;
|
|
|
|
PaymentProvider.prototype.sendSilentSms = function(aNumber, aMessage) {
|
|
_debug && DEBUG("Sending silent message " + aNumber + " - " + aMessage);
|
|
|
|
let request = Services.DOMRequest.createRequest(this._window);
|
|
|
|
if (this._strategy.paymentServiceId === null) {
|
|
DEBUG_E("No payment service ID set. Cannot send silent SMS");
|
|
Services.DOMRequest.fireErrorAsync(request,
|
|
"NO_PAYMENT_SERVICE_ID");
|
|
return request;
|
|
}
|
|
|
|
let smsRequest = new SilentSmsRequest(request);
|
|
smsService.send(this._strategy.paymentServiceId, aNumber, aMessage, true,
|
|
smsRequest);
|
|
return request;
|
|
};
|
|
|
|
PaymentProvider.prototype.observeSilentSms = function(aNumber, aCallback) {
|
|
_debug && DEBUG("observeSilentSms " + aNumber);
|
|
|
|
if (!this._silentSmsObservers) {
|
|
this._silentSmsObservers = {};
|
|
this._silentNumbers = [];
|
|
this._onSilentSmsObserver = this._onSilentSms.bind(this);
|
|
Services.obs.addObserver(this._onSilentSmsObserver,
|
|
kSilentSmsReceivedTopic,
|
|
false);
|
|
}
|
|
|
|
if (!this._silentSmsObservers[aNumber]) {
|
|
this._silentSmsObservers[aNumber] = [];
|
|
this._silentNumbers.push(aNumber);
|
|
smsService.addSilentNumber(aNumber);
|
|
}
|
|
|
|
if (this._silentSmsObservers[aNumber].indexOf(aCallback) == -1) {
|
|
this._silentSmsObservers[aNumber].push(aCallback);
|
|
}
|
|
return;
|
|
};
|
|
|
|
PaymentProvider.prototype.removeSilentSmsObserver = function(aNumber, aCallback) {
|
|
_debug && DEBUG("removeSilentSmsObserver " + aNumber);
|
|
|
|
if (!this._silentSmsObservers || !this._silentSmsObservers[aNumber]) {
|
|
_debug && DEBUG("No observers for " + aNumber);
|
|
return;
|
|
}
|
|
|
|
let index = this._silentSmsObservers[aNumber].indexOf(aCallback);
|
|
if (index != -1) {
|
|
this._silentSmsObservers[aNumber].splice(index, 1);
|
|
if (this._silentSmsObservers[aNumber].length == 0) {
|
|
this._silentSmsObservers[aNumber] = null;
|
|
this._silentNumbers.splice(this._silentNumbers.indexOf(aNumber), 1);
|
|
smsService.removeSilentNumber(aNumber);
|
|
}
|
|
} else if (_debug) {
|
|
DEBUG("No callback found for " + aNumber);
|
|
}
|
|
return;
|
|
};
|
|
|
|
PaymentProvider.prototype._onSilentSms = function(aSubject, aTopic, aData) {
|
|
if (!aSubject || !(aSubject instanceof Ci.nsISmsMessage)) {
|
|
_debug && DEBUG("Invalid subject when receiving silent message!");
|
|
return;
|
|
}
|
|
|
|
let message = aSubject.QueryInterface(Ci.nsISmsMessage);
|
|
|
|
_debug && DEBUG("Got silent message! " + message.sender + " - " + message.body);
|
|
|
|
let number = message.sender;
|
|
if (!number || this._silentNumbers.indexOf(number) == -1) {
|
|
_debug && DEBUG("No observers for " + number);
|
|
return;
|
|
}
|
|
|
|
// If the service ID is null it means that the payment provider asked the
|
|
// user for her MSISDN, so we are in a MT only SMS auth flow. In this case
|
|
// we manually set the service ID to the one corresponding with the SIM
|
|
// that received the SMS.
|
|
if (this._strategy.paymentServiceId === null) {
|
|
let i = 0;
|
|
while(i < gRil.numRadioInterfaces) {
|
|
if (this.iccInfo[i].iccId === message.iccId) {
|
|
this._strategy.paymentServiceId = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
this._silentSmsObservers[number].forEach(function(callback) {
|
|
callback({
|
|
iccId: message.iccId,
|
|
sender: message.sender,
|
|
body: message.body,
|
|
timestamp: message.timestamp,
|
|
sentTimestamp: message.sentTimestamp
|
|
});
|
|
});
|
|
};
|
|
|
|
PaymentProvider.prototype._cleanup = function() {
|
|
if (!this._silentNumbers) {
|
|
return;
|
|
}
|
|
|
|
while (this._silentNumbers.length) {
|
|
let number = this._silentNumbers.pop();
|
|
smsService.removeSilentNumber(number);
|
|
}
|
|
this._silentNumbers = null;
|
|
this._silentSmsObservers = null;
|
|
Services.obs.removeObserver(this._onSilentSmsObserver,
|
|
kSilentSmsReceivedTopic);
|
|
};
|
|
|
|
#else
|
|
|
|
PaymentProvider.prototype.sendSilentSms = function(aNumber, aMessage) {
|
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
|
};
|
|
|
|
PaymentProvider.prototype.observeSilentSms = function(aNumber, aCallback) {
|
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
|
};
|
|
|
|
PaymentProvider.prototype.removeSilentSmsObserver = function(aNumber, aCallback) {
|
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
|
};
|
|
|
|
#endif
|
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentProvider]);
|