Bug 921112 - Expose MCC/MNC in payments on Android. r=mfinkle

This commit is contained in:
Wes Johnston 2013-11-25 09:42:25 -08:00
parent d6dfa4ccda
commit 0dad644b9c
6 changed files with 218 additions and 8 deletions

View File

@ -95,6 +95,11 @@ public class GeckoNetworkManager extends BroadcastReceiver {
NETWORK_UNKNOWN
}
private enum InfoType {
MCC,
MNC
}
private Context mApplicationContext;
private NetworkType mNetworkType = NetworkType.NETWORK_NONE;
private IntentFilter mNetworkFilter = new IntentFilter();
@ -322,4 +327,32 @@ public class GeckoNetworkManager extends BroadcastReceiver {
return false;
}
}
private static int getNetworkOperator(InfoType type) {
TelephonyManager tel = (TelephonyManager)sInstance.mApplicationContext.getSystemService(Context.TELEPHONY_SERVICE);
if (tel == null) {
Log.e(LOGTAG, "Telephony service does not exist");
return -1;
}
String networkOperator = tel.getNetworkOperator();
if (networkOperator == null || networkOperator.length() <= 3) {
return -1;
}
if (type == InfoType.MNC) {
return Integer.parseInt(networkOperator.substring(3));
} else if (type == InfoType.MCC) {
return Integer.parseInt(networkOperator.substring(0, 3));
}
return -1;
}
public static int getMCC() {
return getNetworkOperator(InfoType.MCC);
}
public static int getMNC() {
return getNetworkOperator(InfoType.MNC);
}
}

View File

@ -58,6 +58,7 @@ skip-if = processor == "x86"
[testSessionOOMSave]
[testSessionOOMRestore]
[testSettingsMenuItems]
[testMozPay]
[testSharedPreferences]
# [testShareLink] # see bug 915897
[testSystemPages]

View File

@ -0,0 +1,25 @@
<html>
<head>
<script type="text/javascript">
function start() {
if (!mozPaymentProvider)
window.close();
// We don't have a way to mock these values yet. This check just makes sure the world
// doesn't crash if we ask for them.
var mcc = mozPaymentProvider.mcc;
var mnc = mozPaymentProvider.mnc;
// We use the jwt passed in here to test calling paymentFailed/Success
if (window.location.hash == "#pass")
mozPaymentProvider.paymentSuccess("PAID CORRECTLY");
else if (window.location.hash == "#fail")
mozPaymentProvider.paymentFailed("FAILED CORRECTLY");
else
mozPaymentProvider.paymentFailed("invalid hash " + window.location.hash);
}
document.addEventListener("DOMContentLoaded", start);
</script>
</head>
</html>

View File

@ -0,0 +1,10 @@
package org.mozilla.gecko.tests;
import org.mozilla.gecko.*;
public class testMozPay extends JavascriptTest {
public testMozPay() {
super("testMozPay.js");
}
}

View File

@ -0,0 +1,102 @@
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
/* 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/. */
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
Components.utils.import("resource://gre/modules/SharedPreferences.jsm");
Components.utils.import("resource://gre/modules/commonjs/sdk/core/promise.js");
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
let deferred = 0;
let shouldPass = true;
let reqId = 0;
function getRequestId(increment) {
reqId += increment;
return "Request" + reqId;
}
let paymentSuccess = {
receiveMessage: function(aMsg) {
let msg = aMsg.json;
if (shouldPass) {
do_check_eq(msg.requestId, getRequestId(0));
} else {
do_throw("Test should not have passed");
}
deferred.resolve();
}
}
let paymentFailed = {
receiveMessage: function(aMsg) {
let msg = aMsg.json;
if (shouldPass) {
do_throw("Test should not have failed: " + msg.errorMsg);
} else {
do_check_eq(msg.requestId, getRequestId(0));
do_check_eq(msg.errorMsg, "FAILED CORRECTLY");
}
deferred.resolve();
}
}
add_task(function test_get_set() {
let ui = Cc["@mozilla.org/payment/ui-glue;1"].getService(Ci.nsIPaymentUIGlue);
deferred = Promise.defer();
let id = getRequestId(1);
ui.confirmPaymentRequest(id,
[{ wrappedJSObject: { type: "Fake Provider" } }],
function(aRequestId, type) {
do_check_eq(type, "Fake Provider");
deferred.resolve();
},
function(id, msg) {
do_throw("confirmPaymentRequest should not have failed");
deferred.resolve();
});
yield deferred.promise;
});
add_task(function test_default() {
ppmm.addMessageListener("Payment:Success", paymentSuccess);
ppmm.addMessageListener("Payment:Failed", paymentFailed);
let ui = Cc["@mozilla.org/payment/ui-glue;1"].getService(Ci.nsIPaymentUIGlue);
deferred = Promise.defer();
let id = getRequestId(1);
shouldPass = true;
ui.showPaymentFlow(id,
{
uri: "chrome://roboextender/content/paymentsUI.html",
jwt: "#pass"
},
function(id, msg) {
do_throw("confirmPaymentRequest should not have failed");
deferred.resolve();
});
yield deferred.promise;
deferred = Promise.defer();
let id = getRequestId(1);
shouldPass = false;
ui.showPaymentFlow(id,
{
uri: "chrome://roboextender/content/paymentsUI.html",
jwt: "#fail"
},
function(id, msg) {
do_throw("confirmPaymentRequest should not have failed");
deferred.resolve();
});
yield deferred.promise;
ppmm.removeMessageListener("Payment:Success", paymentSuccess);
ppmm.removeMessageListener("Payment:Failed", paymentFailed);
});
run_next_test();

View File

@ -8,6 +8,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/JNI.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
@ -32,9 +33,17 @@ function paymentFailed(aRequestId) {
}
let paymentTabs = {};
let cancelTabCallbacks = {};
function paymentCanceled(aRequestId) {
return function() {
paymentFailed(aRequestId)();
}
}
function closePaymentTab(aId, aCallback) {
if (paymentTabs[aId]) {
paymentTabs[aId].browser.removeEventListener("TabClose", cancelTabCallbacks[aId]);
delete cancelTabCallbacks[aId];
// We ask the UI to close the selected payment flow.
let content = Services.wm.getMostRecentWindow("navigator:browser");
if (content) {
@ -127,8 +136,39 @@ PaymentUI.prototype = {
tab.browser.addEventListener("DOMContentLoaded", function loadPaymentShim() {
let frame = tab.browser.contentDocument.defaultView;
try {
frame.wrappedJSObject.paymentSuccess = paymentSuccess(aRequestId);
frame.wrappedJSObject.paymentFailed = paymentFailed(aRequestId);
frame.wrappedJSObject.mozPaymentProvider = {
__exposedProps__: {
paymentSuccess: 'r',
paymentFailed: 'r',
mnc: 'r',
mcc: 'r',
},
_getNetworkInfo: function(type) {
let jni = new JNI();
let cls = jni.findClass("org/mozilla/gecko/GeckoNetworkManager");
let method = jni.getStaticMethodID(cls, "get" + type.toUpperCase(), "()I");
let val = jni.callStaticIntMethod(cls, method);
jni.close();
if (val < 0)
return null;
return val;
},
get mnc() {
delete this.mnc;
return this.mnc = this._getNetworkInfo("mnc");
},
get mcc() {
delete this.mcc;
return this.mcc = this._getNetworkInfo("mcc");
},
paymentSuccess: paymentSuccess(aRequestId),
paymentFailed: paymentFailed(aRequestId)
};
} catch (e) {
_error(aRequestId, "ERROR_ADDING_METHODS");
} finally {
@ -136,13 +176,12 @@ PaymentUI.prototype = {
}
}, true);
// fail the payment if the tab is closed on its own
tab.browser.addEventListener("TabClose", function paymentCanceled() {
paymentFailed(aRequestId)();
});
// Store a reference to the tab so that we can close it when the payment succeeds or fails.
paymentTabs[aRequestId] = tab;
cancelTabCallbacks[aRequestId] = paymentCanceled(aRequestId);
// Fail the payment if the tab is closed on its own
tab.browser.addEventListener("TabClose", cancelTabCallbacks[aRequestId]);
},
cleanup: function cleanup() {