diff --git a/apps/settings/index.html b/apps/settings/index.html
index 1b369b1d444f..7a6269e27f9b 100644
--- a/apps/settings/index.html
+++ b/apps/settings/index.html
@@ -71,7 +71,6 @@
-
diff --git a/apps/settings/js/airplane_mode.js b/apps/settings/js/airplane_mode.js
index 28935b6e6dea..38bec712677f 100644
--- a/apps/settings/js/airplane_mode.js
+++ b/apps/settings/js/airplane_mode.js
@@ -10,37 +10,250 @@
var AirplaneMode = {
- element: null,
+ /**
+ * Counter for operstions before radiosafe event
+ * Updated when we toggle radio mode
+ * @private
+ */
+ _ops: 0,
- init: function apm_init() {
- var self = this;
- var settings = window.navigator.mozSettings;
+ /**
+ * Whether or not we are firing the event for airplane mode
+ * @private
+ */
+ _doNotify: false,
- if (!settings) {
+ element: document.getElementById('airplaneMode-input'),
+
+ /**
+ * Enable the radio state
+ */
+ enableRadioSwitch: function() {
+ this.element.disabled = false;
+ },
+
+ /**
+ * Notifies apps that components are in a stable state
+ * This waits until all components are enabled after changing airplane mode
+ * @param {String} the setting name.
+ */
+ notify: function(name) {
+ if (!this._doNotify)
return;
+
+ this._ops--;
+ if (this._ops === 0) {
+ this._doNotify = false;
+ this.enableRadioSwitch();
}
+ },
+
+ _initRadioSwitch: function() {
+ var mobileConnections = window.navigator.mozMobileConnections;
+ var self = this;
+ var isError = false;
+ var setCount = 0;
+
+ var setRadioAfterReqsCalled = function(enabled) {
+ if (setCount !== mobileConnections.length) {
+ return;
+ } else {
+ if (isError) {
+ setAirplaneModeEnabled(enabled);
+ } else {
+ SettingsListener.getSettingsLock().set(
+ {'ril.radio.disabled': !enabled}
+ );
+ }
+ }
+ };
+
+ var doSetRadioEnabled = function doSetRadioEnabled(i, enabled) {
+ var conn = mobileConnections[i];
+ var req = conn.setRadioEnabled(enabled);
+ setCount++;
+
+ req.onsuccess = function() {
+ setRadioAfterReqsCalled(enabled);
+ };
+ req.onerror = function() {
+ isError = true;
+ setRadioAfterReqsCalled(enabled);
+ };
+ };
- this.element = document.getElementById('airplaneMode-input');
+ var setRadioEnabled = function setRadioEnabled(i, enabled) {
+ var conn = mobileConnections[i];
+ if (conn.radioState !== 'enabling' &&
+ conn.radioState !== 'disabling' &&
+ conn.radioState !== null) {
+ doSetRadioEnabled(i, enabled);
+ } else {
+ conn.addEventListener('radiostatechange',
+ function radioStateChangeHandler() {
+ if (conn.radioState == 'enabling' ||
+ conn.radioState == 'disabling' ||
+ conn.radioState == null) {
+ return;
+ }
+ conn.removeEventListener('radiostatechange',
+ radioStateChangeHandler);
+ doSetRadioEnabled(i, enabled);
+ });
+ }
+ };
+
+ var setAirplaneModeEnabled = function setAirplaneModeEnabled(enabled) {
+ isError = false;
+ setCount = 0;
+ // set airplane mode `true`
+ // means setRadioEnabled `false`
+ enabled = !enabled;
+ if (mobileConnections.length == 1) {
+ setRadioEnabled(0, enabled);
+ } else {
+ setRadioEnabled(0, enabled);
+ setRadioEnabled(1, enabled);
+ }
+ };
+
+ SettingsListener.observe('ril.radio.disabled', false, function(value) {
+ self.element.disabled = false;
+ self.element.checked = value;
+ });
- // handle change on radio
this.element.addEventListener('change', function(e) {
this.disabled = true;
- AirplaneModeHelper.setEnabled(this.checked);
+ setAirplaneModeEnabled(this.checked);
});
+ },
- // initial status
- var status = AirplaneModeHelper.getStatus();
- this.element.checked = (status === 'enabled') ? true : false;
- this.element.disabled = false;
+ init: function apm_init() {
+ var mobileConnection = getMobileConnection();
+ var wifiManager = WifiHelper.getWifiManager();
+ var nfcManager = getNfc();
+
+ var settings = Settings.mozSettings;
+ if (!settings)
+ return;
+
+ var self = this;
+ this._initRadioSwitch();
+
+ var mobileDataEnabled = false;
+ settings.addObserver('ril.data.enabled', function(e) {
+ mobileDataEnabled = e.settingValue;
+ self.notify('ril.data.enabled');
+ });
+
+ var bluetoothEnabled = false;
+ var wifiEnabled = false;
+ var geolocationEnabled = false;
+ var nfcEnabled = false;
+ settings.addObserver('geolocation.enabled', function(e) {
+ geolocationEnabled = e.settingValue;
+ self.notify('geolocation.enabled');
+ });
+
+ // when wifi is really enabled, notify if needed
+ window.addEventListener('wifi-enabled', function() {
+ wifiEnabled = true;
+ self.notify('wifi.enabled');
+ });
+
+ // when wifi is really disabled, notify if needed
+ window.addEventListener('wifi-disabled', function() {
+ wifiEnabled = false;
+ self.notify('wifi.enabled');
+ });
+
+ if (window.gBluetooth) {
+ // when bluetooth is really enabled, notify if needed
+ window.addEventListener('bluetooth-adapter-added', function() {
+ bluetoothEnabled = true;
+ self.notify('bluetooth.enabled');
+ });
+
+ // when bluetooth is really disabled, notify if needed
+ window.addEventListener('bluetooth-disabled', function() {
+ bluetoothEnabled = false;
+ self.notify('bluetooth.enabled');
+ });
+ }
+ settings.addObserver('nfc.enabled', function(e) {
+ nfcEnabled = e.settingValue;
+ self.notify('nfc.enabled');
+ });
+
+
+ var restoreMobileData = false;
+ var restoreBluetooth = false;
+ var restoreWifi = false;
+ var restoreGeolocation = false;
+ var restoreNfc = false;
+
+ settings.addObserver('ril.radio.disabled', function(e) {
+ // Reset notification params
+ self._ops = 0;
+ self._doNotify = true;
+
+ if (e.settingValue) {
+ if (mobileConnection) {
+ restoreMobileData = mobileDataEnabled;
+ if (mobileDataEnabled)
+ self._ops++;
+ }
+
+ // Bluetooth.
+ if (window.gBluetooth) {
+ restoreBluetooth = bluetoothEnabled;
+ if (bluetoothEnabled)
+ self._ops++;
+ }
+
+ // Wifi.
+ if (wifiManager) {
+ restoreWifi = wifiEnabled;
+ if (wifiEnabled)
+ self._ops++;
+ }
+
+ // Geolocation
+ restoreGeolocation = geolocationEnabled;
+ if (geolocationEnabled)
+ self._ops++;
+
+ // NFC
+ restoreNfc = nfcEnabled;
+ if (nfcManager) {
+ self._ops++;
+ }
- // handle transition
- AirplaneModeHelper.addEventListener('statechange', function(status) {
- if (status === 'enabled' || status === 'disabled') {
- self.element.checked = (status === 'enabled') ? true : false;
- self.element.disabled = false;
} else {
- self.element.disabled = true;
+ // Don't count mobile data if it's already on
+ if (mobileConnection && !mobileDataEnabled && restoreMobileData)
+ self._ops++;
+
+ // Don't count Bluetooth if it's already on
+ if (window.gBluetooth && !gBluetooth.enabled && restoreBluetooth)
+ self._ops++;
+
+ // Don't count Wifi if it's already on
+ if (wifiManager && !wifiManager.enabled && restoreWifi)
+ self._ops++;
+
+ // Don't count Geolocation if it's already on
+ if (!geolocationEnabled && restoreGeolocation)
+ self._ops++;
+
+ // Don't count NFC if it's already on
+ if (nfcManager && !nfcEnabled && restoreNfc)
+ self._ops++;
}
+
+ // If we have zero operations to perform, enable the radio switch
+ if (self._ops === 0)
+ self.enableRadioSwitch();
});
}
};
diff --git a/apps/settings/js/settings.js b/apps/settings/js/settings.js
index 3bede739f16a..78916c9995aa 100644
--- a/apps/settings/js/settings.js
+++ b/apps/settings/js/settings.js
@@ -803,7 +803,6 @@ window.addEventListener('load', function loadSettings() {
LazyLoader.load(['shared/js/wifi_helper.js'], displayDefaultPanel);
LazyLoader.load([
- 'shared/js/airplane_mode_helper.js',
'js/airplane_mode.js',
'js/battery.js',
'shared/js/async_storage.js',
diff --git a/apps/settings/test/unit/airplane_mode_helper_test.js b/apps/settings/test/unit/airplane_mode_helper_test.js
deleted file mode 100644
index 2e5a2388fe52..000000000000
--- a/apps/settings/test/unit/airplane_mode_helper_test.js
+++ /dev/null
@@ -1,184 +0,0 @@
-/* global MockNavigatorSettings, mocha, AirplaneModeHelper
- */
-'use strict';
-
-requireApp(
- 'settings/shared/test/unit/mocks/mock_navigator_moz_settings.js');
-
-mocha.globals(['AirplaneModeHelper']);
-
-suite('AirplaneModeHelper > ', function() {
- var realMozSettings;
- var kEventName = 'statechange';
- var kCommunicationKey = 'airplaneMode.enabled';
- var kStatusKey = 'airplaneMode.status';
-
- suiteSetup(function() {
- realMozSettings = window.navigator.mozSettings;
- window.navigator.mozSettings = MockNavigatorSettings;
- });
-
- suiteTeardown(function() {
- window.navigator.mozSettings = realMozSettings;
- });
-
- suite('init > ', function() {
- setup(function(done) {
- this.sinon.spy(navigator.mozSettings, 'addObserver');
- require('/shared/js/airplane_mode_helper.js', done);
- });
-
- test('we added observers on ' + kStatusKey, function() {
- assert.isFunction(navigator.mozSettings.mObservers[kStatusKey][0]);
- });
- });
-
- suite('getStatus > ', function() {
- var fakeStatus;
- setup(function() {
- fakeStatus = 'disabling';
- AirplaneModeHelper._cachedStatus = fakeStatus;
- });
- test('getCurrentStatus returns right status', function() {
- assert.equal(AirplaneModeHelper.getStatus(), fakeStatus);
- });
- });
-
- suite('addEventListener > ', function() {
- var fakeEventName = 'thisIsFakeEventName';
- var fakeCallback = function() {};
-
- setup(function() {
- AirplaneModeHelper._callbacks = [];
- });
-
- suite('add event with wrong keyword', function() {
- setup(function() {
- AirplaneModeHelper.addEventListener(fakeEventName, fakeCallback);
- });
- test('can\'t add callbacks', function() {
- assert.equal(AirplaneModeHelper._callbacks.length, 0);
- });
- });
-
- suite('add event with right keyword', function() {
- setup(function() {
- AirplaneModeHelper.addEventListener(kEventName, fakeCallback);
- });
- test('can add callbacks', function() {
- assert.equal(AirplaneModeHelper._callbacks.length, 1);
- });
- });
- });
-
- suite('removeEventListener > ', function() {
- var fakeEventName = 'thisIsFakeEventName';
- var fakeCallback = function() {};
-
- setup(function() {
- AirplaneModeHelper._callbacks = [fakeCallback];
- });
-
- suite('remove event with wrong keyword', function() {
- setup(function() {
- AirplaneModeHelper.removeEventListener(fakeEventName, fakeCallback);
- });
- test('can\'t remove callbacks', function() {
- assert.equal(AirplaneModeHelper._callbacks.length, 1);
- });
- });
-
- suite('remove event with right keyword', function() {
- setup(function() {
- AirplaneModeHelper.removeEventListener(kEventName, fakeCallback);
- });
- test('can remove callbacks', function() {
- assert.equal(AirplaneModeHelper._callbacks.length, 0);
- });
- });
- });
-
- suite('setEnabled > ', function() {
- suite('setEnabled(true) when enabling', function() {
- setup(function() {
- AirplaneModeHelper._cachedStatus = 'enabling';
- AirplaneModeHelper.setEnabled(true);
- });
- test('will do nothing', function() {
- assert.isUndefined(
- window.navigator.mozSettings.mSettings[kCommunicationKey]);
- });
- });
- suite('setEnabled(false) when enabling', function() {
- setup(function() {
- AirplaneModeHelper._cachedStatus = 'enabling';
- AirplaneModeHelper.setEnabled(false);
- });
- test('will do nothing', function() {
- assert.isUndefined(
- window.navigator.mozSettings.mSettings[kCommunicationKey]);
- });
- });
- suite('setEnabled(true) when disabling', function() {
- setup(function() {
- AirplaneModeHelper._cachedStatus = 'disabling';
- AirplaneModeHelper.setEnabled(true);
- });
- test('will do nothing', function() {
- assert.isUndefined(
- window.navigator.mozSettings.mSettings[kCommunicationKey]);
- });
- });
- suite('setEnabled(false) when disabling', function() {
- setup(function() {
- AirplaneModeHelper._cachedStatus = 'disabling';
- AirplaneModeHelper.setEnabled(false);
- });
- test('will do nothing', function() {
- assert.isUndefined(
- window.navigator.mozSettings.mSettings[kCommunicationKey]);
- });
- });
- suite('setEnabled(true) when enabled', function() {
- setup(function() {
- AirplaneModeHelper._cachedStatus = 'enabled';
- AirplaneModeHelper.setEnabled(true);
- });
- test('will do nothing', function() {
- assert.isUndefined(
- window.navigator.mozSettings.mSettings[kCommunicationKey]);
- });
- });
- suite('setEnabled(false) when disabled', function() {
- setup(function() {
- AirplaneModeHelper._cachedStatus = 'disabled';
- AirplaneModeHelper.setEnabled(false);
- });
- test('will do nothing', function() {
- assert.isUndefined(
- window.navigator.mozSettings.mSettings[kCommunicationKey]);
- });
- });
- suite('setEnabled(true) when disabled', function() {
- setup(function() {
- AirplaneModeHelper._cachedStatus = 'disabled';
- AirplaneModeHelper.setEnabled(true);
- });
- test('will change airplane mode status', function() {
- assert.isDefined(
- window.navigator.mozSettings.mSettings[kCommunicationKey]);
- });
- });
- suite('setEnabled(false) when enabled', function() {
- setup(function() {
- AirplaneModeHelper._cachedStatus = 'enabled';
- AirplaneModeHelper.setEnabled(false);
- });
- test('will change airplane mode status', function() {
- assert.isDefined(
- window.navigator.mozSettings.mSettings[kCommunicationKey]);
- });
- });
-
- });
-});
diff --git a/apps/settings/test/unit/messaging_test.js b/apps/settings/test/unit/messaging_test.js
index 1d1fea5ee7a9..837cd3fc60f0 100644
--- a/apps/settings/test/unit/messaging_test.js
+++ b/apps/settings/test/unit/messaging_test.js
@@ -5,11 +5,10 @@ requireApp('settings/shared/test/unit/mocks/mock_navigator_moz_settings.js');
requireApp('settings/test/unit/mock_l10n.js');
-requireApp('settings/shared/test/unit/mocks/mock_settings_listener.js');
+requireApp('settings/shared/js/settings_listener.js');
requireApp('settings/js/messaging.js');
var mocksForMessaging = new MocksHelper([
- 'SettingsListener',
'IccHelper'
]).init();
diff --git a/apps/system/js/airplane_mode.js b/apps/system/js/airplane_mode.js
index 4a3eec1929bf..a52236e13b86 100644
--- a/apps/system/js/airplane_mode.js
+++ b/apps/system/js/airplane_mode.js
@@ -1,13 +1,93 @@
-/* global SettingsListener, AirplaneMode */
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
'use strict';
-(function(exports) {
+var AirplaneMode = {
+ _enabled: null,
+ set enabled(value) {
+ if (value !== this._enabled) {
+ var mobileConnections = window.navigator.mozMobileConnections;
+ var self = this;
+ var isError = false;
+ var setCount = 0;
+
+ var setRadioAfterReqsCalled = function(enabled) {
+ if (setCount !== mobileConnections.length) {
+ return;
+ } else {
+ if (isError) {
+ self._enabled = enabled;
+ setAirplaneModeEnabled(self._enabled);
+ } else {
+ self._enabled = !enabled;
+ SettingsListener.getSettingsLock().set(
+ {'ril.radio.disabled': self._enabled}
+ );
+ }
+ }
+ };
+
+ var doSetRadioEnabled = function doSetRadioEnabled(i, enabled) {
+ var conn = mobileConnections[i];
+ var req = conn.setRadioEnabled(enabled);
+ setCount++;
+
+ req.onsuccess = function() {
+ setRadioAfterReqsCalled(enabled);
+ };
+ req.onerror = function() {
+ isError = true;
+ setRadioAfterReqsCalled(enabled);
+ };
+ };
+
+ var setRadioEnabled = function setRadioEnabled(i, enabled) {
+ var conn = mobileConnections[i];
+ if (conn.radioState !== 'enabling' &&
+ conn.radioState !== 'disabling' &&
+ conn.radioState !== null) {
+ doSetRadioEnabled(i, enabled);
+ } else {
+ conn.addEventListener('radiostatechange',
+ function radioStateChangeHandler() {
+ if (conn.radioState == 'enabling' ||
+ conn.radioState == 'disabling' ||
+ conn.radioState == null) {
+ return;
+ }
+ conn.removeEventListener('radiostatechange',
+ radioStateChangeHandler);
+ doSetRadioEnabled(i, enabled);
+ });
+ }
+ };
+
+ var setAirplaneModeEnabled = function setAirplaneModeEnabled(enabled) {
+ // set airplane mode `true`
+ // means setRadioEnabled `false`
+ enabled = !enabled;
+ if (mobileConnections.length == 1) {
+ setRadioEnabled(0, enabled);
+ } else {
+ setRadioEnabled(0, enabled);
+ setRadioEnabled(1, enabled);
+ }
+ };
- var AirplaneModeServiceHelper = {
- _settings: {
+ setAirplaneModeEnabled(value);
+ }
+ },
+
+ get enabled() {
+ return this._enabled;
+ },
+
+ init: function apm_init() {
+ if (!window.navigator.mozSettings)
+ return;
+
+ var settings = {
// mozSetting state for Data connection, Bluetooth, Wifi, GPS
'ril.data.enabled': false,
'bluetooth.enabled': false,
@@ -21,16 +101,24 @@
'wifi.suspended': false,
'geolocation.suspended': false,
'nfc.suspended': false
- },
+ };
+
+ // observe the corresponding mozSettings
+ for (var key in settings) {
+ (function(settingID) {
+ SettingsListener.observe(settingID, false, function(value) {
+ settings[settingID] = value;
+ });
+ })(key);
+ }
+
// turn off the mozSetting corresponding to `key'
// and remember its initial state by storing it in another setting
- _suspend: function(key) {
- var enabled = this._settings[key + '.enabled'];
- var suspended = this._settings[key + '.suspended'];
-
- if (suspended) {
+ function suspend(key) {
+ var enabled = settings[key + '.enabled'];
+ var suspended = settings[key + '.suspended'];
+ if (suspended)
return;
- }
// remember the state before switching it to false
var sset = {};
@@ -43,11 +131,12 @@
eset[key + '.enabled'] = false;
SettingsListener.getSettingsLock().set(eset);
}
- },
+ }
+
// turn on the mozSetting corresponding to `key'
// if it has been suspended by the airplane mode
- _restore: function(key) {
- var suspended = this._settings[key + '.suspended'];
+ function restore(key) {
+ var suspended = settings[key + '.suspended'];
// clear the 'suspended' state
var sset = {};
@@ -60,381 +149,104 @@
rset[key + '.enabled'] = true;
SettingsListener.getSettingsLock().set(rset);
}
- },
- isEnabled: function(key) {
- return this._settings[key + '.enabled'];
- },
- isSuspended: function(key) {
- return this._settings[key + '.suspended'];
- },
- init: function() {
- var self = this;
+ }
- // observe the corresponding mozSettings
- for (var key in this._settings) {
- (function(settingID) {
- SettingsListener.observe(settingID, false, function(value) {
- self._settings[settingID] = value;
- });
- })(key);
- }
- },
- updateStatus: function(value) {
- var mozSettings = window.navigator.mozSettings;
- var bluetooth = window.navigator.mozBluetooth;
- var wifiManager = window.navigator.mozWifiManager;
- var mobileData = window.navigator.mozMobileConnections[0] &&
- window.navigator.mozMobileConnections[0].data;
- var fmRadio = window.navigator.mozFMRadio;
+ var mozSettings = window.navigator.mozSettings;
+ var bluetooth = window.navigator.mozBluetooth;
+ var wifiManager = window.navigator.mozWifiManager;
+ var mobileData = window.navigator.mozMobileConnections[0] &&
+ window.navigator.mozMobileConnections[0].data;
+ var fmRadio = window.navigator.mozFMRadio;
+
+ // Note that we don't restore Wifi tethering when leaving airplane mode
+ // because Wifi tethering can't be switched on before data connection is
+ // established.
+ var self = this;
+ function updateStatus(value) {
if (value) {
+ // Entering airplane mode.
+ self.enabled = true;
+
// Turn off mobile data:
// we toggle the mozSettings value here just for the sake of UI,
// platform RIL disconnects mobile data when
// 'ril.radio.disabled' is true.
if (mobileData) {
- this._suspend('ril.data');
+ suspend('ril.data');
}
// Turn off Bluetooth.
if (bluetooth) {
- this._suspend('bluetooth');
+ suspend('bluetooth');
}
// Turn off Wifi and Wifi tethering.
if (wifiManager) {
- this._suspend('wifi');
+ suspend('wifi');
SettingsListener.getSettingsLock().set({
'tethering.wifi.enabled': false
});
}
// Turn off Geolocation.
- this._suspend('geolocation');
+ suspend('geolocation');
// Turn off NFC
- this._suspend('nfc');
+ suspend('nfc');
// Turn off FM Radio.
if (fmRadio && fmRadio.enabled) {
fmRadio.disable();
}
} else {
- // Note that we don't restore Wifi tethering when leaving airplane mode
- // because Wifi tethering can't be switched on before data connection is
- // established.
+ // Leaving airplane mode.
+ self.enabled = false;
// Don't attempt to turn on mobile data if it's already on
- if (mobileData && !this._settings['ril.data.enabled']) {
- this._restore('ril.data');
+ if (mobileData && !settings['ril.data.enabled']) {
+ restore('ril.data');
}
// Don't attempt to turn on Bluetooth if it's already on
if (bluetooth && !bluetooth.enabled) {
- this._restore('bluetooth');
+ restore('bluetooth');
}
// Don't attempt to turn on Wifi if it's already on
if (wifiManager && !wifiManager.enabled) {
- this._restore('wifi');
+ restore('wifi');
}
// Don't attempt to turn on Geolocation if it's already on
- if (!this._settings['geolocation.enabled']) {
- this._restore('geolocation');
+ if (!settings['geolocation.enabled']) {
+ restore('geolocation');
}
- if (!this._settings['nfc.enabled']) {
- this._restore('nfc');
+ if (!settings['nfc.enabled']) {
+ restore('nfc');
}
}
}
- };
-
- // main
- var AirplaneMode = {
- /*
- * We will cache the helper as our internal value
- */
- _serviceHelper: AirplaneModeServiceHelper,
-
- /*
- * This is an internal key to store current state of AirplaneMode
- */
- _enabled: null,
-
- /*
- * This is an event mapping table that will help us wait for
- * specific event from its manager to make sure we are now
- * in airplane mode or not.
- */
- _checkedActionsMap: {
- wifi: {
- enabled: 'wifi-enabled',
- disabled: 'wifi-disabled'
- },
- bluetooth: {
- enabled: 'bluetooth-adapter-added',
- disabled: 'bluetooth-disabled'
- }
- },
-
- /*
- * When turning on / off airplane mode, we will start watching
- * needed events to make sure we are in airplane mode or not.
- *
- * @param {boolean} value
- * @param {Object} checkedActions
- */
- watchEvents: function(value, checkedActions) {
- var self = this;
- for (var serviceName in this._checkedActionsMap) {
-
- // if we are waiting for specific service
- if (serviceName in checkedActions) {
- var action = value ? 'disabled' : 'enabled';
- var eventName = this._checkedActionsMap[serviceName][action];
-
- // then we will start watch events coming from its manager
- window.addEventListener(eventName,
- (function(eventName, serviceName) {
- return function toUpdateAirplaneMode() {
- window.removeEventListener(eventName, toUpdateAirplaneMode);
- checkedActions[serviceName] = true;
- self._updateAirplaneModeStatus(checkedActions);
- };
- }(eventName, serviceName)));
- }
- }
- },
-
- /*
- * This is a ES5 feature that can help the others easily get/set
- * AirplaneMode.
- *
- * @param {boolean} value
- */
- set enabled(value) {
- if (value !== this._enabled) {
- var self = this;
- var setCount = 0;
- var isError = false;
- var checkedActions = this._getCheckedActions(value);
- var mobileConnections = window.navigator.mozMobileConnections;
-
- // start watching events
- this.watchEvents(value, checkedActions);
-
- var setRadioAfterReqsCalled = function(enabled) {
- if (setCount !== mobileConnections.length) {
- return;
- } else {
- if (isError) {
- self._enabled = enabled;
- setAirplaneModeEnabled(self._enabled);
- } else {
- self._enabled = !enabled;
- checkedActions['conn'] = true;
- self._updateAirplaneModeStatus(checkedActions);
- }
- }
- };
- var doSetRadioEnabled = function doSetRadioEnabled(i, enabled) {
- var conn = mobileConnections[i];
- var req = conn.setRadioEnabled(enabled);
- setCount++;
-
- req.onsuccess = function() {
- setRadioAfterReqsCalled(enabled);
- };
- req.onerror = function() {
- isError = true;
- setRadioAfterReqsCalled(enabled);
- };
- };
-
- var setRadioEnabled = function setRadioEnabled(i, enabled) {
- var conn = mobileConnections[i];
- if (conn.radioState !== 'enabling' &&
- conn.radioState !== 'disabling' &&
- conn.radioState !== null) {
- doSetRadioEnabled(i, enabled);
- } else {
- conn.addEventListener('radiostatechange',
- function radioStateChangeHandler() {
- if (conn.radioState == 'enabling' ||
- conn.radioState == 'disabling' ||
- conn.radioState == null) {
- return;
- }
- conn.removeEventListener('radiostatechange',
- radioStateChangeHandler);
- doSetRadioEnabled(i, enabled);
- });
- }
- };
-
- var setAirplaneModeEnabled = function setAirplaneModeEnabled(enabled) {
- // set airplane mode `true`
- // means setRadioEnabled `false`
- enabled = !enabled;
- for (var i = 0; i < mobileConnections.length; i++) {
- setRadioEnabled(i, enabled);
- }
- };
-
- setAirplaneModeEnabled(value);
- this._serviceHelper.updateStatus(value);
- }
- },
-
- /*
- * This is a ES5 feature that can help the others easily get AirplaneMode
- * states.
- *
- * @return {boolean}
- */
- get enabled() {
- return this._enabled;
- },
-
- /*
- * In order to make sure all needed managers work successfully. We have to
- * use this method to update airplaneMode related keys to tell
- * AirplaneModeHelper our current states and is finised or not.
- */
- _updateAirplaneModeStatus: function(checkActions) {
- var self = this;
- var areAllActionsDone;
-
- areAllActionsDone = this._areCheckedActionsAllDone(checkActions);
-
- if (areAllActionsDone) {
- var req = SettingsListener.getSettingsLock().set({
- 'airplaneMode.enabled': self._enabled,
- 'airplaneMode.status': self._enabled ? 'enabled' : 'disabled',
- // NOTE
- // this is for backward compatibility,
- // because we will update this value only when airplane mode
- // is on / off, it will not affect apps using this value
- 'ril.radio.disabled': self._enabled
- });
- } else {
- // keep updating the status to reflect current status
- SettingsListener.getSettingsLock().set({
- 'airplaneMode.status': self._enabled ? 'enabling' : 'disabling'
- });
- }
- },
-
- /*
- * By default, these three API takes longer time and with success / error
- * callback. we just have to wait for these three items.
- *
- * @param {boolean} value
- * @return {Object} checkedActions
- */
- _getCheckedActions: function(value) {
- // we have to re-init all need-to-check managers
- var checkedActions = {};
-
- if (value === true) {
- // check connection
- if (window.navigator.mozMobileConnections) {
- checkedActions.conn = false;
- }
-
- // check bluetooth
- if (this._serviceHelper.isEnabled('bluetooth')) {
- checkedActions.bluetooth = false;
- }
-
- // check wifi
- if (this._serviceHelper.isEnabled('wifi')) {
- checkedActions.wifi = false;
- }
- }
- else {
- // check connection
- if (window.navigator.mozMobileConnections) {
- checkedActions.conn = false;
- }
-
- // check bluetooth
- if (this._serviceHelper.isSuspended('bluetooth')) {
- checkedActions.bluetooth = false;
- }
-
- // check wifi
- if (this._serviceHelper.isSuspended('wifi')) {
- checkedActions.wifi = false;
- }
- }
-
- return checkedActions;
- },
-
- /*
- * We have to use this method to check whether all actions
- * are done or not.
- *
- * @return {boolean}
- */
- _areCheckedActionsAllDone: function(checkedActions) {
- for (var key in checkedActions) {
- if (checkedActions[key] === false) {
- return false;
- }
- }
- return true;
- },
-
- /*
- * Entry point
- */
- init: function apm_init() {
- var self = this;
-
- if (!window.navigator.mozSettings) {
- return;
- }
-
- var mozSettings = window.navigator.mozSettings;
- var mozMobileConnections = window.navigator.mozMobileConnections;
-
- this._serviceHelper.init();
-
- // Initialize radio state
- var request =
- SettingsListener.getSettingsLock().get('airplaneMode.enabled');
-
- request.onsuccess = function() {
- var enabled = request.result['airplaneMode.enabled'];
- self.enabled = enabled;
- };
-
- // monitor airplaneMode communication key change
- mozSettings.addObserver('airplaneMode.enabled', function(e) {
- self.enabled = e.settingValue;
- });
-
- /*
- * If we are in airplane mode and the user just dial out an
- * emergency call, we have to exit airplane mode.
- */
- mozMobileConnections[0].addEventListener('radiostatechange',
- function() {
- if (mozMobileConnections[0].radioState === 'enabled' &&
- self._enabled === true) {
- self.enabled = false;
- }
- });
- }
- };
+ // Initialize radio state
+ var request = SettingsListener.getSettingsLock().get('ril.radio.disabled');
+ request.onsuccess = function() {
+ var enabled = !!request.result['ril.radio.disabled'];
+ // See bug 933659
+ // Gecko stops using the settings key 'ril.radio.disabled' to turn
+ // off RIL radio. We need to remove the code that checks existence of the
+ // new API after bug 856553 lands.
+ self.enabled = enabled;
+ };
+
+ // Observe settings changes
+ mozSettings.addObserver('ril.radio.disabled', function(e) {
+ updateStatus(e.settingValue);
+ });
+ }
+};
- exports.AirplaneMode = AirplaneMode;
-})(window);
if (document && (document.readyState === 'complete' ||
document.readyState === 'interactive')) {
diff --git a/apps/system/test/unit/airplane_mode_test.js b/apps/system/test/unit/airplane_mode_test.js
deleted file mode 100644
index c09072f5c218..000000000000
--- a/apps/system/test/unit/airplane_mode_test.js
+++ /dev/null
@@ -1,384 +0,0 @@
-/* global MockNavigatorSettings, AirplaneMode, MocksHelper,
- MockNavigatorMozMobileConnections, SettingsListener,
- MockLock, MockWifiManager, MockBluetooth */
-'use strict';
-
-requireApp(
- 'system/shared/test/unit/mocks/mock_navigator_moz_mobile_connections.js');
-requireApp('system/shared/test/unit/mocks/mock_settings_listener.js');
-requireApp('system/shared/test/unit/mocks/mock_navigator_moz_settings.js');
-requireApp('system/test/unit/mock_bluetooth.js');
-requireApp('system/test/unit/mock_wifi_manager.js');
-requireApp('system/js/airplane_mode.js');
-
-var mocksForAirplaneMode = new MocksHelper([
- 'Bluetooth',
- 'WifiManager',
- 'SettingsListener',
- 'NavigatorMozMobileConnections'
-]).init();
-
-suite('system/airplane_mode.js', function() {
- var realSettings;
- var realMobileConnections;
-
- mocksForAirplaneMode.attachTestHelpers();
-
- suiteSetup(function() {
- realSettings = window.navigator.mozSettings;
- window.navigator.mozSettings = MockNavigatorSettings;
-
- realMobileConnections = window.navigator.mozMobileConnections;
- window.navigator.mozMobileConnections = MockNavigatorMozMobileConnections;
- });
-
- suiteTeardown(function() {
- window.navigator.mozSettings = realSettings;
-
- MockNavigatorMozMobileConnections.mTeardown();
- window.navigator.mozMobileConnections = realMobileConnections;
- });
-
- setup(function() {
- // we will do a lot of manipulations on SettingsListener,
- // let's clean it all for every test
- MockLock.clear();
- });
-
- suite('init > ', function() {
- suiteSetup(function() {
- AirplaneMode.init();
- });
- test('AirplaneModeServiceHelper is registered', function() {
- assert.isObject(AirplaneMode._serviceHelper);
- });
- test('AirplaneModeServiceHelper starts observing key changes',
- function() {
- var checkedServiceKeys = [
- 'bluetooth.enabled',
- 'wifi.enabled',
- 'geolocation.enabled',
- 'nfc.enabled'
- ];
- checkedServiceKeys.forEach(function(key) {
- assert.ok(key in SettingsListener.mCallbacks);
- });
- });
- });
-
- suite('set enabled to true', function() {
- suite('but _enabled is true already, do nothing', function() {
- setup(function() {
- this.sinon.spy(AirplaneMode._serviceHelper, 'updateStatus');
- AirplaneMode._enabled = true;
- AirplaneMode.enabled = true;
- });
- test('nothing happend', function() {
- assert.isFalse(AirplaneMode._serviceHelper.updateStatus.called);
- });
- });
-
- suite('_enabled is false, keep running', function() {
- setup(function() {
- this.sinon.stub(AirplaneMode._serviceHelper, 'updateStatus');
- AirplaneMode._enabled = false;
-
- // we have to make eventListeners to the newest state
- MockNavigatorMozMobileConnections.mAddMobileConnection();
- });
-
- teardown(function() {
- // we have to make eventListeners to the newest state
- MockNavigatorMozMobileConnections.mTeardown();
- });
-
- suite('conn0 is enabling, conn1 is enabling', function() {
- setup(function() {
- setConnection(0, 'enabling');
- setConnection(1, 'enabling');
- AirplaneMode.enabled = true;
- });
- test('we will cache doSetRadioEnabled for later use', function() {
- var conns = window.navigator.mozMobileConnections;
- assert.isFunction(
- conns[0].mEventListeners.radiostatechange[0]);
- assert.isFunction(
- conns[1].mEventListeners.radiostatechange[0]);
- });
- });
-
- suite('conn0 is enabling, conn1 is enabled', function() {
- setup(function() {
- setConnection(0, 'enabling');
- setConnection(1, 'enabled');
- AirplaneMode.enabled = true;
- });
- test('no further steps because setCount is not 2', function() {
- var conns = window.navigator.mozMobileConnections;
- assert.isFunction(
- conns[0].mEventListeners.radiostatechange[0]);
- assert.isFunction(
- conns[1].mCachedRadioEnabledReq.onsuccess);
-
-
- // but because setCount is not 2, we will not
- // execute further steps
- conns[1].mCachedRadioEnabledReq.onsuccess();
-
- var checkedActions = AirplaneMode._getCheckedActions(true);
- assert.isFalse(checkedActions.conn);
- });
- });
-
- suite('conn0 is enabled, conn1 is enabled', function() {
- // we will wait for these two services
- suiteSetup(function() {
- setSettingOnServiceHelper('wifi.enabled', true);
- setSettingOnServiceHelper('bluetooth.enabled', true);
- });
- suiteTeardown(function() {
- setSettingOnServiceHelper('wifi.enabled', false);
- setSettingOnServiceHelper('bluetooth.enabled', false);
- });
- setup(function() {
- setConnection(0, 'enabled');
- setConnection(1, 'enabled');
- AirplaneMode.enabled = true;
- });
- test('no further steps because we are waiting other events',
- function() {
- var conns = window.navigator.mozMobileConnections;
- assert.isFunction(
- conns[0].mCachedRadioEnabledReq.onsuccess);
- assert.isFunction(
- conns[1].mCachedRadioEnabledReq.onsuccess);
-
- // assume radio is done
- conns[0].mCachedRadioEnabledReq.onsuccess();
- conns[1].mCachedRadioEnabledReq.onsuccess();
-
- // but because we are still waiting for the other window event,
- // we we will not execute further steps
- var checkedActions = AirplaneMode._getCheckedActions(true);
- assert.isFalse(
- AirplaneMode._areCheckedActionsAllDone(checkedActions));
-
- var lock = getLastSettingsLock();
- assert.equal(lock['airplaneMode.status'], 'enabling');
- });
- });
-
- suite('conn0 is enabled, conn1 is enabled', function() {
- setup(function() {
- setConnection(0, 'enabled');
- setConnection(1, 'enabled');
- AirplaneMode.enabled = true;
- });
- test('all other services are also done, we are in airplaneMode',
- function() {
- var conns = window.navigator.mozMobileConnections;
- assert.isFunction(
- conns[0].mCachedRadioEnabledReq.onsuccess);
- assert.isFunction(
- conns[1].mCachedRadioEnabledReq.onsuccess);
-
- // setRadioEnabled operation is done
- conns[0].mCachedRadioEnabledReq.onsuccess();
- conns[1].mCachedRadioEnabledReq.onsuccess();
-
- emitEvent('wifi-disabled');
- emitEvent('bluetooth-disabled');
-
- var lock = getLastSettingsLock();
- assert.equal(lock['airplaneMode.status'], 'enabled');
- });
- });
- });
- });
-
- suite('set enabled to false', function() {
- suite('but _enabled is false already, do nothing', function() {
- setup(function() {
- this.sinon.spy(AirplaneMode._serviceHelper, 'updateStatus');
- AirplaneMode._enabled = false;
- AirplaneMode.enabled = false;
- });
- test('nothing happend', function() {
- assert.isFalse(AirplaneMode._serviceHelper.updateStatus.called);
- });
- });
-
- suite('_enabled is true, keep running', function() {
- setup(function() {
- this.sinon.stub(AirplaneMode._serviceHelper, 'updateStatus');
- AirplaneMode._enabled = true;
-
- // we have to make eventListeners to the newest state
- MockNavigatorMozMobileConnections.mAddMobileConnection();
- });
-
- teardown(function() {
- // we have to make eventListeners to the newest state
- MockNavigatorMozMobileConnections.mTeardown();
- });
-
- suite('conn0 is disabling, conn1 is disabling', function() {
- setup(function() {
- setConnection(0, 'disabling');
- setConnection(1, 'disabling');
- AirplaneMode.enabled = false;
- });
- test('we will cache doSetRadioEnabled for later use', function() {
- var conns = window.navigator.mozMobileConnections;
- assert.isFunction(
- conns[0].mEventListeners.radiostatechange[0]);
- assert.isFunction(
- conns[1].mEventListeners.radiostatechange[0]);
- });
- });
-
- suite('conn0 is disabling, conn1 is disabled', function() {
- setup(function() {
- setConnection(0, 'disabling');
- setConnection(1, 'disabled');
-
- // AirplaneMode._checkedActions.conn = false;
- AirplaneMode.enabled = false;
- });
- test('no further steps because setCount is not 2', function() {
- var conns = window.navigator.mozMobileConnections;
- assert.isFunction(
- conns[0].mEventListeners.radiostatechange[0]);
- assert.isFunction(
- conns[1].mCachedRadioEnabledReq.onsuccess);
-
- // but because setCount is not 2, we will not
- // execute further steps
- conns[1].mCachedRadioEnabledReq.onsuccess();
- // assert.isFalse(AirplaneMode._checkedActions.conn);
- });
- });
-
- suite('conn0 is disabled, conn1 is disabled', function() {
- suiteSetup(function() {
- setSettingOnServiceHelper('wifi.suspended', true);
- setSettingOnServiceHelper('bluetooth.suspended', true);
- });
- suiteTeardown(function() {
- setSettingOnServiceHelper('wifi.suspended', false);
- setSettingOnServiceHelper('bluetooth.suspended', false);
- });
- setup(function() {
- setConnection(0, 'disabled');
- setConnection(1, 'disabled');
- AirplaneMode.enabled = false;
- });
- test('no further steps because we are waiting other events',
- function() {
- var conns = window.navigator.mozMobileConnections;
- assert.isFunction(
- conns[0].mCachedRadioEnabledReq.onsuccess);
- assert.isFunction(
- conns[1].mCachedRadioEnabledReq.onsuccess);
-
- // setRadioEnabled operation is done
- conns[0].mCachedRadioEnabledReq.onsuccess();
- conns[1].mCachedRadioEnabledReq.onsuccess();
-
- // but because we are still waiting for the other window event,
- // we we will not execute further steps
- var checkedActions = AirplaneMode._getCheckedActions(false);
- assert.isFalse(
- AirplaneMode._areCheckedActionsAllDone(checkedActions));
-
- var lock = getLastSettingsLock();
- assert.equal(lock['airplaneMode.status'], 'disabling');
- });
- });
-
- suite('conn0 is disabled, conn1 is disabled', function() {
- setup(function() {
- setConnection(0, 'disabled');
- setConnection(1, 'disabled');
- AirplaneMode.enabled = false;
- });
- test('all other services are also done, we are leaving airplaneMode',
- function() {
- var conns = window.navigator.mozMobileConnections;
- assert.isFunction(
- conns[0].mCachedRadioEnabledReq.onsuccess);
- assert.isFunction(
- conns[1].mCachedRadioEnabledReq.onsuccess);
-
- // setRadioEnabled operation is done
- conns[0].mCachedRadioEnabledReq.onsuccess();
- conns[1].mCachedRadioEnabledReq.onsuccess();
-
- emitEvent('wifi-enabled');
- emitEvent('bluetooth-adapter-added');
-
- var lock = getLastSettingsLock();
- assert.equal(lock['airplaneMode.status'], 'disabled');
- });
- });
- });
- });
-
- suite('AirplaneMode is enabled now', function() {
- suiteSetup(function() {
- // we need registered radiostatechange event
- AirplaneMode.init();
- });
- suite('but users want to dial out an emergency call', function() {
- setup(function() {
- AirplaneMode._enabled = true;
- setConnection(0, 'enabled');
- setConnection(1, 'enabled');
- });
- test('we will leave airplane mode', function() {
- var conns = window.navigator.mozMobileConnections;
-
- // got a radiostatechange from gecko
- conns[0].mEventListeners.radiostatechange[0]();
-
- // setRadioEnabled operation is done
- conns[0].mCachedRadioEnabledReq.onsuccess();
- conns[1].mCachedRadioEnabledReq.onsuccess();
-
- emitEvent('wifi-enabled');
- emitEvent('bluetooth-adapter-added');
-
- var lock = getLastSettingsLock();
- assert.equal(lock['airplaneMode.status'], 'disabled');
- });
- });
- });
-
-
- // test helpers
-
- function setSettingOnServiceHelper(key, value) {
- AirplaneMode._serviceHelper._settings[key] = value;
- }
-
- function setConnection(connIndex, status) {
- MockNavigatorMozMobileConnections[connIndex].radioState = status;
- }
-
- function setServiceEnable(serviceName, enabled) {
- Object.defineProperty(window.navigator, serviceName, {
- configurable: true,
- enabled: enabled
- });
- }
-
- function emitEvent(eventName) {
- var evt = document.createEvent('CustomEvent');
- evt.initCustomEvent(eventName, true, false, null);
- window.dispatchEvent(evt);
- }
-
- function getLastSettingsLock() {
- return MockLock.locks[MockLock.locks.length - 1];
- }
-});
diff --git a/build/settings.js b/build/settings.js
index 04d3ca9439d0..d387aa2df6a9 100644
--- a/build/settings.js
+++ b/build/settings.js
@@ -234,8 +234,6 @@ function execute(options) {
'ril.mms.retrieval_mode': 'automatic-home',
'ril.mms.authtype': 'notDefined',
'dom.mms.operatorSizeLimitation': 307200,
- 'airplaneMode.enabled': false,
- 'airplaneMode.status': 'disabled',
'ril.radio.preferredNetworkType': '',
'ril.radio.disabled': false,
'ril.supl.apn': '',
diff --git a/shared/js/airplane_mode_helper.js b/shared/js/airplane_mode_helper.js
deleted file mode 100644
index 520a9901550c..000000000000
--- a/shared/js/airplane_mode_helper.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/* exported AirplaneModeHelper */
-'use strict';
-
-/*
- * AirplaneModeHelper is a helper that makes apps enable / disable
- * airplane mode easily. It will expose two methods for you :
- * 1. AirplaneModeHelper.setEnabled();
- * 2. AirplaneModeHelper.addEventListener('statechange', callback)
- * 3. AirplaneModeHelper.removeEventListener('statechange', callback)
- * 3. AirplaneModeHelper.getStatus(callback);
- */
-(function(exports) {
-
- // constants
- const kEventName = 'statechange';
- const kCommunicationKey = 'airplaneMode.enabled';
- const kStatusKey = 'airplaneMode.status';
-
- // main
- var AirplaneModeHelper = {
- _mozSettings: window.navigator.mozSettings,
- _callbacks: [],
- _cachedStatus: '',
- getStatus: function() {
- return this._cachedStatus;
- },
- addEventListener: function(eventName, callback) {
- if (eventName === kEventName) {
- this._callbacks.push(callback);
- }
- },
- removeEventListener: function(eventName, callback) {
- if (eventName === kEventName) {
- var index = this._callbacks.indexOf(callback);
- if (index >= 0) {
- this._callbacks.splice(index, 1);
- }
- }
- },
- setEnabled: function(enabled) {
- var status = this.getStatus();
-
- if (status === 'enabling' || status === 'disabling') {
- // do nothing when transition
- }
- else {
- if (enabled && status === 'enabled' ||
- !enabled && status === 'disabled') {
- return;
- }
-
- var setObj = {};
- setObj[kCommunicationKey] = enabled;
- this._mozSettings.createLock().set(setObj);
- }
- },
- init: function() {
- var self = this;
-
- // init _cachedStatus
- var lock = window.navigator.mozSettings.createLock();
- var req = lock.get(kStatusKey);
- req.onsuccess = function() {
- self._cachedStatus = req.result[kStatusKey];
- self._callbacks.forEach(function(callback) {
- callback(self._cachedStatus);
- });
- };
-
- this._mozSettings.addObserver(kStatusKey, function(evt) {
- var currentStatus = evt.settingValue;
- self._cachedStatus = currentStatus;
- self._callbacks.forEach(function(callback) {
- callback(currentStatus);
- });
- });
- }
- };
-
- exports.AirplaneModeHelper = AirplaneModeHelper;
-
- // by default, we will add observer immediately for you right after
- // you include this helper
- AirplaneModeHelper.init();
-})(this);
diff --git a/shared/test/unit/mocks/mock_navigator_moz_mobile_connections.js b/shared/test/unit/mocks/mock_navigator_moz_mobile_connections.js
index c96507617307..e7447b1d94e7 100644
--- a/shared/test/unit/mocks/mock_navigator_moz_mobile_connections.js
+++ b/shared/test/unit/mocks/mock_navigator_moz_mobile_connections.js
@@ -4,17 +4,12 @@
function MockMobileconnection() {
var props = ['voice', 'data', 'iccId', 'radioState', 'iccInfo'];
var eventListeners = null;
- var radioEnabledReq = null;
function mnmmc_init() {
props.forEach(function(prop) {
_mock[prop] = null;
});
- eventListeners = {
- 'iccinfochange': [],
- 'radiostatechange': []
- };
- radioEnabledReq = {};
+ eventListeners = { 'iccinfochange': [] };
}
function mnmmc_addEventListener(type, callback) {
@@ -48,19 +43,11 @@
}
}
- function mnmmc_setRadioEnabled() {
- return radioEnabledReq;
- }
-
var _mock = {
addEventListener: mnmmc_addEventListener,
removeEventListener: mnmmc_removeEventListener,
triggerEventListeners: mnmmc_triggerEventListeners,
- setRadioEnabled: mnmmc_setRadioEnabled,
mTeardown: mnmmc_init,
- get mCachedRadioEnabledReq() {
- return radioEnabledReq;
- },
get mEventListeners() {
return eventListeners;
}