Skip to content

Commit b31a0a5

Browse files
committed
Revert "Revert "Merge pull request mozilla-b2g#12000 from nullaus/operator-variant""
This reverts commit 8b15a33.
1 parent 937b3af commit b31a0a5

File tree

9 files changed

+266
-77
lines changed

9 files changed

+266
-77
lines changed

apps/system/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@
223223
<script defer src="js/identity.js"></script>
224224

225225
<!-- Operator Variant Mechanism -->
226+
<script defer src="shared/js/operator_variant_helper.js"></script>
226227
<script defer src="js/operator_variant/operator_variant.js"></script>
227228

228229
<!-- Crash Reporter -->

apps/system/js/operator_variant/operator_variant.js

Lines changed: 43 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,61 +4,39 @@
44
'use strict';
55

66
(function OperatorVariant() {
7-
/**
8-
* Get the mcc/mnc info that has been stored in the settings.
9-
*/
10-
11-
var settings = window.navigator.mozSettings;
12-
if (!settings)
13-
return;
14-
15-
var iccSettings = { mcc: '-1', mnc: '-1' };
167

17-
// Read the mcc/mnc settings, then trigger callback.
18-
function getICCSettings(callback) {
19-
var transaction = settings.createLock();
20-
var mccKey = 'operatorvariant.mcc';
21-
var mncKey = 'operatorvariant.mnc';
8+
// Cache the values we've seen.
9+
var iccSettings = { mcc: -1, mnc: -1 };
2210

23-
var mccRequest = transaction.get(mccKey);
24-
mccRequest.onsuccess = function() {
25-
iccSettings.mcc = mccRequest.result[mccKey] || '0';
26-
var mncRequest = transaction.get(mncKey);
27-
mncRequest.onsuccess = function() {
28-
iccSettings.mnc = mncRequest.result[mncKey] || '0';
29-
callback();
30-
};
31-
};
11+
/**
12+
* Utility function to pad a number with leading zeros and transform it
13+
* into a string.
14+
*
15+
* @param {Number} num The number to pad with leading zeros.
16+
* @param {Number} length The final length the number should have,
17+
* in characters.
18+
*/
19+
function padLeft(num, length) {
20+
var r = String(num);
21+
while (r.length < length) {
22+
r = '0' + r;
23+
}
24+
return r;
3225
}
3326

34-
3527
/**
36-
* Compare the cached mcc/mnc info with the one in the SIM card,
37-
* and retrieve/apply APN settings if they differ.
28+
* Check the APN settings on startup and when the SIM card is changed.
3829
*/
30+
var operatorVariantHelper =
31+
new OperatorVariantHelper(applySettings,
32+
'operatorvariant.customization',
33+
true);
3934

40-
if (!IccHelper.enabled)
41-
return;
42-
43-
// Check the mcc/mnc information on the SIM card.
44-
function checkICCInfo() {
45-
if (!IccHelper.iccInfo || IccHelper.cardState !== 'ready')
46-
return;
47-
48-
// ensure that the iccSettings have been retrieved
49-
if ((iccSettings.mcc < 0) || (iccSettings.mnc < 0))
50-
return;
51-
52-
// XXX sometimes we get 0/0 for mcc/mnc, even when cardState === 'ready'...
53-
var mcc = IccHelper.iccInfo.mcc || '0';
54-
var mnc = IccHelper.iccInfo.mnc || '0';
55-
if (mcc === '0')
56-
return;
57-
58-
// avoid setting APN (and operator variant) settings if mcc/mnc codes
59-
// changes.
60-
IccHelper.removeEventListener('iccinfochange', checkICCInfo);
35+
// Listen for future changes in MCC/MNC values to support hot swapping
36+
// of SIM cards.
37+
operatorVariantHelper.listen();
6138

39+
function applySettings(mcc, mnc) {
6240
// same SIM card => do nothing
6341
if ((mcc == iccSettings.mcc) && (mnc == iccSettings.mnc)) {
6442
var apnSettingsKey = 'ril.data.apnSettings';
@@ -79,22 +57,34 @@
7957
iccSettings.mcc = mcc;
8058
iccSettings.mnc = mnc;
8159
retrieveOperatorVariantSettings(applyOperatorVariantSettings);
60+
8261
// use mcc, mnc to load and apply WAP user agent profile url
8362
retrieveWAPUserAgentProfileSettings(applyWAPUAProfileUrl);
84-
};
63+
}
8564

8665
// Load and query APN database, then trigger callback on results.
8766
function retrieveOperatorVariantSettings(callback) {
88-
var OPERATOR_VARIANT_FILE = 'shared/resources/apn.json';
67+
// This json file should always be accessed from the root instead of the
68+
// current working base URL so that it can work in unit-tests as well
69+
// as during normal run time.
70+
var OPERATOR_VARIANT_FILE = '/shared/resources/apn.json';
8971

9072
var xhr = new XMLHttpRequest();
9173
xhr.open('GET', OPERATOR_VARIANT_FILE, true);
9274
xhr.responseType = 'json';
9375
xhr.onreadystatechange = function() {
9476
if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status === 0)) {
9577
var apn = xhr.response;
78+
79+
// The apn.json generator strips out leading zeros for mcc values. No
80+
// need for padding in this instance.
9681
var mcc = iccSettings.mcc;
97-
var mnc = iccSettings.mnc;
82+
83+
// We must pad the mnc value and turn it into a string otherwise
84+
// we could *fail* to load the appropriate settings for single digit
85+
// *mnc* values!
86+
var mnc = padLeft(iccSettings.mnc, 2);
87+
9888
// get a list of matching APNs
9989
var compatibleAPN = apn[mcc] ? (apn[mcc][mnc] || []) : [];
10090
callback(compatibleAPN);
@@ -152,7 +142,7 @@
152142
const DEFAULT_MMS_SIZE_LIMITATION = 300 * 1024;
153143

154144
// store relevant APN settings
155-
var transaction = settings.createLock();
145+
var transaction = navigator.mozSettings.createLock();
156146
for (var type in apnPrefNames) {
157147
var apn = {};
158148
for (var i = 0; i < result.length; i++) {
@@ -203,7 +193,7 @@
203193
var apnSettings = [];
204194
var apnTypeCandidates = ['default', 'supl', 'mms'];
205195
var checkedType = [];
206-
var transaction = settings.createLock();
196+
var transaction = navigator.mozSettings.createLock();
207197
// converts apns to new format
208198
for (var i = 0; i < result.length; i++) {
209199
var sourceAPNItem = result[i];
@@ -251,14 +241,6 @@
251241
var WAP_UA_PROFILE_FILE = '/resources/wapuaprof.json';
252242
var DEFAULT_KEY = '000000';
253243

254-
function padLeft(num, length) {
255-
var r = String(num);
256-
while (r.length < length) {
257-
r = '0' + r;
258-
}
259-
return r;
260-
}
261-
262244
var xhr = new XMLHttpRequest();
263245
xhr.open('GET', WAP_UA_PROFILE_FILE, true);
264246
xhr.responseType = 'json';
@@ -281,16 +263,9 @@
281263

282264
// apply the user agent profile to mozsettings.
283265
function applyWAPUAProfileUrl(uaProfile) {
284-
var transaction = settings.createLock();
266+
var transaction = navigator.mozSettings.createLock();
285267
var urlValue = uaProfile ? uaProfile.url : undefined;
286268
transaction.set({'wap.UAProf.url': urlValue});
287269
}
288270

289-
/**
290-
* Check the APN settings on startup and when the SIM card is changed.
291-
*/
292-
293-
getICCSettings(checkICCInfo);
294-
IccHelper.addEventListener('iccinfochange', checkICCInfo);
295271
})();
296-

apps/system/test/unit/internet_sharing_test.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,6 @@ suite('internet sharing > ', function() {
6565
var cset = {};
6666
cset[key] = value;
6767
MockNavigatorSettings.createLock().set(cset);
68-
MockNavigatorSettings.mTriggerObservers(key, {
69-
'settingName': key,
70-
'settingValue': value
71-
});
7268
}
7369
// suite 1 from no sim card to sim card inserted, and re-inserted again.
7470
suite('from null sim to sim 1 >>', function() {
@@ -158,7 +154,7 @@ suite('internet sharing > ', function() {
158154
changeSettings(KEY_USB_TETHERING, true);
159155
var testSet = [
160156
{'key': PREFIX_ASYNC_STORAGE_USB + TEST_ICCID1, 'result': true},
161-
{'key': PREFIX_ASYNC_STORAGE_WIFI + TEST_ICCID1, 'result': null},
157+
{'key': PREFIX_ASYNC_STORAGE_WIFI + TEST_ICCID1, 'result': false},
162158
{'key': PREFIX_ASYNC_STORAGE_USB + TEST_ICCID2, 'result': null},
163159
{'key': PREFIX_ASYNC_STORAGE_WIFI + TEST_ICCID2, 'result': null}];
164160
assertAynscStorageEquals(testSet);
@@ -167,7 +163,7 @@ suite('internet sharing > ', function() {
167163
test('sim1 removed', function() {
168164
changeCardState('absent', null);
169165
IccHelper.mProps['cardState'] = 'absent';
170-
IccHelper.mProps['iccInfo'] = null;
166+
IccHelper.mProps['iccInfo'] = {};
171167
IccHelper.mTriggerEventListeners('cardstatechange', {});
172168
var testSet = [{'key': KEY_USB_TETHERING, 'result': false},
173169
{'key': KEY_WIFI_HOTSPOT, 'result': false}];
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
'use strict';
2+
3+
requireApp('system/shared/test/unit/mocks/mock_icc_helper.js');
4+
requireApp('system/shared/test/unit/mocks/mock_navigator_moz_mobile_connection.js');
5+
requireApp('system/shared/test/unit/mocks/mock_navigator_moz_settings.js');
6+
7+
requireApp('system/shared/js/operator_variant_helper.js');
8+
9+
var mocksForOperatorVariant = new MocksHelper([
10+
'IccHelper'
11+
]).init();
12+
13+
suite('operator variant', function() {
14+
const TEST_NETWORK_MCC = 1;
15+
16+
const EXPECTED_DATA_MNC = 1;
17+
const EXPECTED_DATA_ICC_INFO = {
18+
mcc: TEST_NETWORK_MCC,
19+
mnc: EXPECTED_DATA_MNC
20+
};
21+
22+
const EXPECTED_MMS_MNC = 2;
23+
const EXPECTED_MMS_ICC_INFO = {
24+
mcc: TEST_NETWORK_MCC,
25+
mnc: EXPECTED_MMS_MNC
26+
};
27+
28+
const NULL_ICC_INFO = { mcc: 0, mnc: 0 };
29+
const PERSIST_KEY = 'operator_variant_test.customize';
30+
31+
const DATA_KEYS_VALUES = [
32+
{ key: 'ril.data.carrier', value: 'Test Network' },
33+
{ key: 'ril.data.apn', value: 'internet' },
34+
{ key: 'ril.data.user', value: 'user' },
35+
{ key: 'ril.data.passwd', value: 'password' },
36+
{ key: 'ril.data.httpProxyHost', value: '127.0.0.1' },
37+
{ key: 'ril.data.httpProxyPort', value: '8080' },
38+
{ key: 'ril.data.authtype', value: 'none' }
39+
];
40+
41+
const MMS_KEYS_VALUES = [
42+
{ key: 'ril.mms.carrier', value: 'Test Network with MMS' },
43+
{ key: 'ril.mms.apn', value: 'mms.internet' },
44+
{ key: 'ril.mms.mmsc', value: 'http://127.0.0.1' },
45+
{ key: 'ril.mms.mmsproxy', value: '127.0.0.1' },
46+
{ key: 'ril.mms.mmsport', value: '8080' }
47+
];
48+
49+
var realMozMobileConnection;
50+
var realMozSettings;
51+
52+
mocksForOperatorVariant.attachTestHelpers();
53+
suiteSetup(function() {
54+
MockIccHelper.mProps.cardState = 'ready';
55+
56+
realMozMobileConnection = navigator.mozMobileConnection;
57+
navigator.mozMobileConnection = MockNavigatorMozMobileConnection;
58+
59+
realMozSettings = navigator.mozSettings;
60+
navigator.mozSettings = MockNavigatorSettings;
61+
62+
// The code being run in the anonymous function in this js file is dependent
63+
// on the mocks being setup properly. If we load it with the rest of the js
64+
// files it will always fail to run.
65+
requireApp('system/js/operator_variant/operator_variant.js');
66+
});
67+
68+
suiteTeardown(function() {
69+
navigator.mozMobileConnection = realMozMobileConnection;
70+
navigator.mozSettings = realMozSettings;
71+
});
72+
73+
setup(function() {
74+
MockNavigatorMozMobileConnection.iccInfo = NULL_ICC_INFO;
75+
MockNavigatorMozMobileConnection.triggerEventListeners('iccinfochange', {});
76+
});
77+
78+
teardown(function() {
79+
MockNavigatorMozMobileConnection.iccInfo = NULL_ICC_INFO;
80+
MockNavigatorMozMobileConnection.triggerEventListeners('iccinfochange', {});
81+
});
82+
83+
function setObservers(keyValues, observer, remove) {
84+
if (remove === undefined) {
85+
remove = false;
86+
}
87+
88+
if (remove) {
89+
keyValues.forEach(function(data) {
90+
MockNavigatorSettings.removeObserver(data.key, this);
91+
}, observer.bound);
92+
observer.bound = null;
93+
}
94+
else {
95+
observer.bound = observer.func.bind(observer);
96+
keyValues.forEach(function(data) {
97+
MockNavigatorSettings.addObserver(data.key, this);
98+
}, observer.bound);
99+
}
100+
}
101+
102+
test('operator variant data apn', function(done) {
103+
var observer = {
104+
bound: null,
105+
expected: DATA_KEYS_VALUES.length,
106+
seen: 0,
107+
func: function(event) {
108+
DATA_KEYS_VALUES.forEach(function(data) {
109+
if (data.key == event.settingName) {
110+
assert.equal(
111+
event.settingValue,
112+
data.value,
113+
'Wrong Data setting value'
114+
);
115+
++this.seen;
116+
}
117+
}, this);
118+
119+
if (this.seen == this.expected) {
120+
setObservers(DATA_KEYS_VALUES, this, true);
121+
done();
122+
}
123+
}
124+
};
125+
126+
setObservers(DATA_KEYS_VALUES, observer);
127+
128+
MockNavigatorMozMobileConnection.iccInfo = EXPECTED_DATA_ICC_INFO;
129+
MockNavigatorMozMobileConnection.triggerEventListeners('iccinfochange', {});
130+
});
131+
132+
test('operator variant mms apn', function(done) {
133+
var observer = {
134+
bound: null,
135+
expected: MMS_KEYS_VALUES.length,
136+
seen: 0,
137+
func: function(event) {
138+
MMS_KEYS_VALUES.forEach(function(data) {
139+
140+
if (data.key == event.settingName) {
141+
assert.equal(
142+
event.settingValue,
143+
data.value,
144+
'Wrong MMS setting value'
145+
);
146+
++this.seen;
147+
}
148+
}, this);
149+
150+
if (this.seen == this.expected) {
151+
setObservers(MMS_KEYS_VALUES, this, true);
152+
done();
153+
}
154+
}
155+
};
156+
157+
setObservers(MMS_KEYS_VALUES, observer);
158+
159+
MockNavigatorMozMobileConnection.iccInfo = EXPECTED_MMS_ICC_INFO;
160+
MockNavigatorMozMobileConnection.triggerEventListeners('iccinfochange', {});
161+
});
162+
163+
});

0 commit comments

Comments
 (0)