Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,76 @@
/**
* This module is used to show/hide addon menuItem based on the number of
* current installed addons.
*
* @module AddonsItem
*/
define(function(require) {
'use strict';
var AddonManager = require('modules/addon_manager');
function AddonsItem(element) {
this._enabled = false;
this._element = element;
this.init();
}
AddonsItem.prototype = {
/**
* Set current status of addonsItem
*
* @access public
* @param {Boolean} enabled
* @memberOf AddonsItem
*/
set enabled(enabled) {
if (this._enabled === enabled) {
return;
} else {
this._enabled = enabled;
if (this._enabled) {
this._updateAddonSectionVisibility();
}
}
},
/**
* Get current status of addonsItem
*
* @access public
* @memberOf AddonsItem
*/
get enabled() {
return this._enabled;
},
/**
* Initialization
*
* @access private
* @memberOf AddonsItem
* @return {Promise}
*/
init: function() {
var _handleEvent = this._updateAddonSectionVisibility.bind(this);
AddonManager.addons.observe('insert', _handleEvent);
AddonManager.addons.observe('remove', _handleEvent);
AddonManager.addons.observe('reset', _handleEvent);
this._updateAddonSectionVisibility();
},
/**
* Update addon section visibility based on _addonCount
*
* @memberOf AddonsItem
*/
_updateAddonSectionVisibility: function() {
this._element.hidden = AddonManager.length === 0;
}
};
return function(element) {
return new AddonsItem(element);
};
});

View file

@ -0,0 +1,116 @@
/**
* This module is used to control the background stuff when users
* toggle on/off airplane mode checkbox.
*
* @module panels/root/airplane_mode_item
*/
define(function(require) {
'use strict';
var AirplaneModeHelper = require('shared/airplane_mode_helper');
/**
* @alias module:panels/root/airplane_mode_item
* @class AirplaneModeItem
* @param {HTMLElement} element the checkbox for airplane mode
* @returns {AirplaneModeItem}
*/
function AirplaneModeItem(element) {
this._itemEnabled = false;
this._element = element;
this.init();
this._boundAPMStateChange = this._onAPMStateChange.bind(this);
}
AirplaneModeItem.prototype = {
/**
* The value indicates whether the module is responding.
*
* @access public
* @memberOf AirplaneModeItem.prototype
* @type {Boolean}
*/
set enabled(value) {
if (this._itemEnabled === value) {
return;
} else {
this._itemEnabled = value;
if (this._itemEnabled) {
AirplaneModeHelper.addEventListener('statechange',
this._boundAPMStateChange);
} else {
AirplaneModeHelper.removeEventListener('statechange',
this._boundAPMStateChange);
}
}
},
/**
* The value indicates whether the module is responding.
*
* @access public
* @memberOf AirplaneModeItem.prototype
* @type {Boolean}
*/
get enabled() {
return this._itemEnabled;
},
/**
* This function is used to reflect current status of APM to checkbox
*
* @access private
* @memberOf AirplaneModeItem.prototype
* @param {String} status current status of APM
* @type {Function}
*/
_onAPMStateChange: function ami_onAPMStateChange(status) {
if (status === 'enabled' || status === 'disabled') {
this._element.checked = (status === 'enabled') ? true : false;
this._element.disabled = false;
} else {
this._element.disabled = true;
}
},
/**
* Initialize function
*
* @access public
* @memberOf AirplaneModeItem.prototype
* @type {Function}
*/
init: function ami_init() {
AirplaneModeHelper.ready(function() {
// handle change on radio
this._element.addEventListener('change', () => {
this._element.setAttribute('disabled', true);
AirplaneModeHelper.setEnabled(this._element.checked);
});
// initial status
var status = AirplaneModeHelper.getStatus();
this._element.checked = (status === 'enabled') ? true : false;
// Bug 1217717 disable the Airplane mode interaction
// before the wifi panel is ready
this._element.disabled = true;
window.addEventListener('wificontext-ready', this);
}.bind(this));
},
handleEvent: function ami_handleEvent(evt) {
switch (evt.type) {
// Bug 1217717 enable the Airplane mode interaction
// once the wifi panel is ready
case 'wificontext-ready':
window.removeEventListener('wificontext-ready', this);
this._element.disabled = false;
break;
}
}
};
return function ctor_airplane_mode_item(element) {
return new AirplaneModeItem(element);
};
});

View file

@ -0,0 +1,78 @@
/**
* The moudle supports displaying battery information on an element.
*
* @module panels/root/battery_item
*/
define(function(require) {
'use strict';
var Battery = require('modules/battery');
/**
* @alias module:panels/root/battery_item
* @class BatteryItem
* @requires module:modules/battery
* @param {HTMLElement} element
The element displaying the battery information
* @returns {BatteryItem}
*/
function BatteryItem(element) {
this._enabled = false;
this._element = element;
this._boundRefreshText = this._refreshText.bind(this, element);
}
BatteryItem.prototype = {
/**
* Refresh the text based on the Battery module.
*
* @access private
* @memberOf BatteryItem.prototype
* @param {HTMLElement} element
The element displaying the battery information
*/
_refreshText: function b_refreshText(element) {
if (!document.l10n) {
return;
}
document.l10n.setAttributes(element,
'battery-level-percent', { level: Battery.level });
if (element.hidden) {
element.hidden = false;
}
},
/**
* The value indicates whether the module is responding.
*
* @access public
* @memberOf BatteryItem.prototype
* @type {Boolean}
*/
get enabled() {
return this._enabled;
},
set enabled(value) {
if (this._enabled === value) {
return;
}
this._enabled = value;
if (this._enabled) {
Battery.observe('level', this._boundRefreshText);
Battery.observe('state', this._boundRefreshText);
this._boundRefreshText();
} else {
Battery.unobserve('level', this._boundRefreshText);
Battery.unobserve('state', this._boundRefreshText);
}
}
};
return function ctor_batteryItem(element) {
return new BatteryItem(element);
};
});

View file

@ -0,0 +1,111 @@
/**
* The moudle supports displaying bluetooth information on an element.
*
* @module panels/root/bluetooth_item
*/
define(function(require) {
'use strict';
var SettingsService = require('modules/settings_service');
var BtContext = require('modules/bluetooth/bluetooth_context');
var _debug = false;
var debug = function() {};
if (_debug) {
debug = function bti_debug(msg) {
console.log('--> [BluetoothItem]: ' + msg);
};
}
/**
* @alias module:panels/root/bluetooth_item
* @class BluetoothItem
* @requires module:modules/bluetooth
* @param {HTMLElement} element
The element displaying the bluetooth information
* @return {BluetoothItem}
*/
function BluetoothItem(element) {
this._enabled = false;
this._element = element;
this._boundRefreshMenuDescription =
this._refreshMenuDescription.bind(this, element);
}
BluetoothItem.prototype = {
/**
* Refresh the text based on the Bluetooth module enabled/disabled,
* paired devices information.
*
* @access private
* @memberOf BluetoothItem.prototype
* @param {HTMLElement} element
The element displaying the bluetooth information
*/
_refreshMenuDescription: function bt__refreshMenuDescription(element) {
if (!document.l10n) {
return;
}
if (BtContext.enabled) {
if (BtContext.numberOfPairedDevices === 0) {
element.setAttribute('data-l10n-id', 'bt-status-nopaired');
} else {
document.l10n.setAttributes(element, 'bt-status-paired',
{
name: BtContext.firstPairedDeviceName,
n: BtContext.numberOfPairedDevices - 1
});
}
} else {
element.setAttribute('data-l10n-id', 'bt-status-turnoff');
}
},
/**
* The value indicates whether the module is responding.
*
* @access public
* @memberOf BluetoothItem.prototype
* @type {Boolean}
*/
get enabled() {
return this._enabled;
},
set enabled(value) {
if (this._enabled === value) {
return;
}
this._enabled = value;
if (this._enabled) {
BtContext.observe('enabled', this._boundRefreshMenuDescription);
BtContext.observe('numberOfPairedDevices',
this._boundRefreshMenuDescription);
this._boundRefreshMenuDescription();
} else {
BtContext.unobserve('enabled', this._boundRefreshMenuDescription);
BtContext.unobserve('numberOfPairedDevices',
this._boundRefreshMenuDescription);
}
},
/**
* Navigate new/old Bluetooth panel via version of mozBluetooth API.
*
* @access private
* @memberOf BluetoothItem.prototype
* @type {Function}
*/
_navigatePanelWithVersionCheck:
function bt__navigatePanelWithVersionCheck() {
debug('navigate bluetooth panel');
SettingsService.navigate('bluetooth');
}
};
return function ctor_bluetoothItem(element) {
return new BluetoothItem(element);
};
});

View file

@ -0,0 +1,91 @@
/* global SettingsListener */
/**
* This module display Find My Device's enabled/disabled state on an
* element.
*
* @module panels/root/findmydevice_item
*/
define(function(require) {
'use strict';
/**
* @alias module:panels/root/findmydevice_item
* @class FindMyDeviceItem
* @param {HTMLElement} element
The element displaying Find My Device's enabled state
* @returns {FindMyDeviceItem}
*/
function FindMyDeviceItem(element) {
this._itemEnabled = false;
this._FMDEnabled = false;
this._boundRefreshText = this._refreshText.bind(this, element);
this._boundFMDEnabledChanged = this._onFMDEnabledChanged.bind(this);
}
FindMyDeviceItem.prototype = {
/**
* Refresh the text based on Find My Device's enabled state
*
* @access private
* @memberOf FindMyDeviceItem.prototype
* @param {HTMLElement} element
The element showing Find My Device's enabled state
*/
_refreshText: function fmd_refresh_text(element) {
if (!document.l10n) {
return;
}
element.setAttribute('data-l10n-id',
this._FMDEnabled ? 'enabled' : 'disabled');
element.hidden = false;
},
/**
* Listener for changes in Find My Device's enabled state. Updates the
* text if this item is enabled.
*
* @access private
* @memberOf FindMyDeviceItem.prototype
* @param {Boolean} value
The current enabled state for Find My Device
*/
_onFMDEnabledChanged: function fmd_enabled_changed(value) {
this._FMDEnabled = value;
if (this._itemEnabled) {
this._boundRefreshText();
}
},
/**
* The value indicates whether the module is responding.
*
* @access public
* @memberOf FindMyDeviceItem.prototype
* @type {Boolean}
*/
get enabled() {
return this._itemEnabled;
},
set enabled(value) {
if (this._itemEnabled === value) {
return;
}
this._itemEnabled = value;
if (this._itemEnabled) {
SettingsListener.observe('findmydevice.enabled', false,
this._boundFMDEnabledChanged);
} else {
SettingsListener.unobserve('findmydevice.enabled',
this._boundFMDEnabledChanged);
}
}
};
return function ctor_findMyDeviceItem(element) {
return new FindMyDeviceItem(element);
};
});

View file

@ -0,0 +1,69 @@
/**
* The moudle supports displaying language information on an element.
*
* @module panels/root/language_item
*/
define(function(require) {
'use strict';
var LanguageList = require('shared/language_list');
/**
* @alias module:panels/root/language_item
* @class LanguageItem
* @param {HTMLElement} element
The element displaying the language information
* @returns {LanguageItem}
*/
function LanguageItem(element) {
this._enabled = false;
this._boundRefreshText = this._refreshText.bind(this, element);
}
LanguageItem.prototype = {
/**
* Refresh the text based on the language setting.
*
* @access private
* @memberOf LanguageItem.prototype
* @param {HTMLElement} element
The element displaying the language information
*/
_refreshText: function l_refeshText(element) {
// display the current locale in the main panel
LanguageList.get(function displayLang(languages, currentLanguage) {
element.textContent = LanguageList.wrapBidi(
currentLanguage, languages[currentLanguage]);
});
},
/**
* The value indicates whether the module is responding.
*
* @access public
* @memberOf LanguageItem.prototype
* @type {Boolean}
*/
get enabled() {
return this._enabled;
},
set enabled(value) {
if (this._enabled === value || !document.l10n) {
return;
}
this._enabled = value;
if (this._enabled) {
document.addEventListener('DOMRetranslated', this._boundRefreshText);
this._boundRefreshText();
} else {
document.removeEventListener('DOMRetranslated', this._boundRefreshText);
}
}
};
return function ctor_languageItem(element) {
return new LanguageItem(element);
};
});

View file

@ -0,0 +1,29 @@
/** Load only panels supported by this platform; never invent hardware values. */
(function() {
'use strict';
var definitions = [
['BluetoothItem', 'bluetooth_item', !!navigator.mozBluetooth, '.bluetooth-desc'],
['NFCItem', 'nfc_item', !!navigator.mozNfc, '.nfc-settings'],
['LanguageItem', 'language_item', true, '.language-desc'],
['BatteryItem', 'battery_item', !!(navigator.battery || navigator.mozBattery), '.battery-desc'],
['FindMyDeviceItem', 'findmydevice_item', !!navigator.mozId, '.findmydevice-desc'],
['StorageUSBItem', 'storage_usb_item', !!navigator.getDeviceStorages, '.media-storage-section, #menuItem-enableStorage'],
['StorageAppItem', 'storage_app_item', !!navigator.getDeviceStorage, '.application-storage-desc'],
['WifiItem', 'wifi_item', !!navigator.mozWifiManager, '#wifi-desc'],
['ScreenLockItem', 'screen_lock_item', true, '.screenLock-desc'],
['SimSecurityItem', 'sim_security_item', !!navigator.mozMobileConnections, '.simCardLock-desc']
];
var supported = definitions.filter(function(item) {return item[2];});
define('panels/root/low_priority_items', supported.map(function(item) {
return 'panels/root/' + item[1];
}), function() {
var modules = arguments, items = {};
supported.forEach(function(item, index) {items[item[0]] = modules[index];});
definitions.filter(function(item) {return !item[2];}).forEach(function(item) {
Array.prototype.forEach.call(document.querySelectorAll(item[3]), function(element) {
(element.closest('li') || element).hidden = true;
});
});
return items;
});
})();

View file

@ -0,0 +1,50 @@
/**
* The moudle supports displaying nfc toggle on an element.
*
* @module panels/root/nfc_item
*/
define(function(require) {
'use strict';
var SettingsListener = require('shared/settings_listener');
/**
* @alias module:panels/root/nfc_item
* @class NFCItem
* @param {Object} elements
* @param {HTMLElement} elements.nfcMenuItem
* @param {HTMLElement} elements.nfcCheckBox
* @returns {NFCItem}
*/
function NFCItem(elements) {
if (!navigator.mozNfc) {
return;
}
elements.nfcMenuItem.hidden = false;
this._checkbox = elements.nfcCheckBox;
this._checkbox.addEventListener('change', () => this._onCheckboxChanged());
SettingsListener.observe('nfc.status', undefined,
(status) => this._onNfcStatusChanged(status));
}
NFCItem.prototype = {
// disabling on change to prevent double clicking and remove toggle
// flickering before nfcManger will change nfc.status
_onCheckboxChanged: function ni_onCheckboxChanged() {
this._checkbox.disabled = true;
},
_onNfcStatusChanged: function ni_onNfcStatusChanged(status) {
if (status === 'enabling' || status === 'disabling') {
this._checkbox.disabled = true;
} else if (status === 'enabled' || status === 'disabled') {
this._checkbox.disabled = false;
}
}
};
return function ctor_nfcItem(elements) {
return new NFCItem(elements);
};
});

View file

@ -0,0 +1,134 @@
define(function(require) {
'use strict';
var SettingsService = require('modules/settings_service');
var SettingsPanel = require('modules/settings_panel');
var Root = require('panels/root/root');
var AirplaneModeItem = require('panels/root/airplane_mode_item');
var ThemesItem = require('panels/root/themes_item');
var AddonsItem = require('panels/root/addons_item');
var STKItem = require('panels/root/stk_item');
var queryRootForLowPriorityItems = function(panel) {
// This is a map from the module name to the object taken by the constructor
// of the module.
return {
'BluetoothItem': panel.querySelector('.bluetooth-desc'),
'NFCItem': {
nfcMenuItem: panel.querySelector('.nfc-settings'),
nfcCheckBox: panel.querySelector('#nfc-input')
},
'LanguageItem': panel.querySelector('.language-desc'),
'BatteryItem': panel.querySelector('.battery-desc'),
'FindMyDeviceItem': panel.querySelector('.findmydevice-desc'),
'StorageUSBItem': {
mediaStorageDesc: panel.querySelector('.media-storage-desc'),
usbStorage: panel.querySelector('#menuItem-enableStorage'),
usbEnabledInfoBlock: panel.querySelector('.usb-desc'),
mediaStorageSection: panel.querySelector('.media-storage-section')
},
'StorageAppItem': panel.querySelector('.application-storage-desc'),
'WifiItem': panel.querySelector('#wifi-desc'),
'ScreenLockItem': panel.querySelector('.screenLock-desc'),
'SimSecurityItem': panel.querySelector('.simCardLock-desc')
};
};
return function ctor_root_panel() {
var root;
var airplaneModeItem;
var themesItem;
var addonsItem;
var stkItem;
var activityDoneButton;
var lowPriorityRoots = null;
var initLowPriorityItemsPromise = null;
var initLowPriorityItems = function(rootElements) {
if (!initLowPriorityItemsPromise) {
initLowPriorityItemsPromise = new Promise(function(resolve) {
require(['panels/root/low_priority_items'], resolve);
}).then(function(itemCtors) {
var result = {};
Object.keys(rootElements).forEach(function(name) {
var itemCtor = itemCtors[name];
if (itemCtor) {
result[name] = itemCtor(rootElements[name]);
}
});
return result;
});
}
return initLowPriorityItemsPromise;
};
return SettingsPanel({
onInit: function rp_onInit(panel) {
root = Root();
root.init(panel);
airplaneModeItem =
AirplaneModeItem(panel.querySelector('.airplaneMode-input'));
themesItem =
ThemesItem(panel.querySelector('.themes-section'));
addonsItem =
AddonsItem(panel.querySelector('#addons-section'));
stkItem = STKItem({
iccMainHeader: panel.querySelector('#icc-mainheader'),
iccEntries: panel.querySelector('#icc-entries')
});
activityDoneButton = panel.querySelector('#activityDoneButton');
activityDoneButton.addEventListener('click', function() {
SettingsService.back();
});
// If the device supports dsds, callSettings must be changed 'href'
// for navigating call-iccs panel first to let users choose simcard
var mozMobileConnections = navigator.mozMobileConnections;
if (mozMobileConnections && mozMobileConnections.length > 1) {
var callItem = document.getElementById('menuItem-callSettings');
callItem.setAttribute('href', '#call-iccs');
}
var idleObserver = {
time: 3,
onidle: function() {
navigator.removeIdleObserver(idleObserver);
lowPriorityRoots = queryRootForLowPriorityItems(panel);
initLowPriorityItems(lowPriorityRoots).then(function(items) {
Object.keys(items).forEach((key) => items[key].enabled = true);
});
}
};
navigator.addIdleObserver(idleObserver);
},
onShow: function rp_onShow(panel) {
airplaneModeItem.enabled = true;
themesItem.enabled = true;
addonsItem.enabled = true;
if (initLowPriorityItemsPromise) {
initLowPriorityItemsPromise.then(function(items) {
Object.keys(items).forEach((key) => items[key].enabled = true);
});
}
},
onHide: function rp_onHide() {
themesItem.enabled = false;
addonsItem.enabled = false;
if (initLowPriorityItemsPromise) {
initLowPriorityItemsPromise.then(function(items) {
Object.keys(items).forEach((key) => items[key].enabled = false);
});
}
},
onUninit: function rp_onUninit() {
airplaneModeItem.enabled = false;
}
});
};
});

View file

@ -0,0 +1,109 @@
/* global TelephonySettingHelper */
/**
* The module loads scripts used by the root panel. In the future these scripts
* must be converted to AMD modules. Implementation details please refer to
* {@link Root}.
*
* @module root/root
*/
define(function(require) {
'use strict';
var LazyLoader = require('shared/lazy_loader');
/**
* @alias module:root/root
* @class Root
* @requires module:shared/lazy_loader
* @returns {Root}
*/
function Root() {}
Root.prototype = {
_panel: null,
_loadScripts: function root_loadScripts() {
/**
* Enable or disable the menu items related to the ICC card
* relying on the card and radio state.
*/
LazyLoader.load([
'js/firefox_accounts/menu_loader.js',
'js/dsds_settings.js',
'js/telephony_settings.js',
'js/telephony_items_handler.js'
], function() {
TelephonySettingHelper
.init()
.then(function telephonySettingInitDone() {
window.dispatchEvent(new CustomEvent('telephony-settings-loaded'));
});
});
},
/**
* Update the sim related items based on mozMobileConnections.
*/
_showSimItems: function root_showSimItems(panel) {
var mozMobileConnections = navigator.mozMobileConnections;
if (mozMobileConnections) {
if (mozMobileConnections.length === 1) { // single sim
var duelSimItem =
this._panel.querySelector('#simCardManager-settings');
duelSimItem.hidden = true;
} else { // DSDS
var simItem = this._panel.querySelector('#simSecurity-settings');
simItem.hidden = true;
}
} else {
// hide telephony panels
var elements = ['#call-settings',
'#data-connectivity',
'#messaging-settings',
'#simSecurity-settings',
'#simCardManager-settings'];
elements.forEach(el => {
this._panel.querySelector(el).hidden = true;
});
}
},
/**
* Update the developer menu item based on the preference.
*/
_showDeveloperMenuItem: function root_showDeveloperMenuItem() {
var developerItem = this._panel.querySelector(
'[data-show-name="developer.menu.enabled"]');
if (developerItem && navigator.mozSettings) {
return navigator.mozSettings.createLock()
.get('developer.menu.enabled').then(
function(result) {
developerItem.hidden = !result['developer.menu.enabled'];
}, function(error) {
console.error(error);
});
} else {
return Promise.resolve();
}
},
// To delay the show/hide in root panel will cause extra screen reflow,
// it can be checked by Toggle on Developer > Flash Repainted Area.
init: function root_init(panel) {
this._panel = panel;
// Load the necessary scripts after the UI update
setTimeout(this._loadScripts);
// Show NFC panel when supported
var nfcItem = panel.querySelector('.nfc-settings');
nfcItem.hidden = !navigator.mozNfc;
// Show proper SIM panel
this._showSimItems();
// Show developer panel when necessary
this._showDeveloperMenuItem();
}
};
return function ctor_root() {
return new Root();
};
});

View file

@ -0,0 +1,60 @@
define(function(require) {
'use strict';
var SettingsListener = require('shared/settings_listener');
function ScreenLockItem(element) {
this._itemEnabled = false;
this._lockscreenEnable = false;
this._lockscreenEnableEvent = 'lockscreen.enabled';
this._lockscreenPasscodeEnableEvent = 'lockscreen.passcode-lock.enabled';
this._element = element;
this._boundUpdateEnable = this._updateEnable.bind(this);
this._boundUpdatePasscodeEnable = this._updatePasscodeEnable.bind(this);
}
ScreenLockItem.prototype = {
set enabled(value) {
if (value === this._itemEnabled) {
return;
} else {
this._itemEnabled = value;
if (this._itemEnabled) {
SettingsListener.observe(this._lockscreenEnableEvent, false,
this._boundUpdateEnable);
SettingsListener.observe(this._lockscreenPasscodeEnableEvent, false,
this._boundUpdatePasscodeEnable);
} else {
SettingsListener.unobserve(this._lockscreenEnableEvent,
this._boundUpdateEnable);
SettingsListener.unobserve(this._lockscreenPasscodeEnableEvent,
this._boundUpdatePasscodeEnable);
}
}
},
get enabled() {
return this._itemEnabled;
},
_updateEnable: function sl_updateEnable(enabled) {
this._lockscreenEnable = enabled;
var l10nId = enabled ? 'screenLock-enabled-with-no-passcode' : 'disabled';
this._element.setAttribute('data-l10n-id', l10nId);
},
_updatePasscodeEnable: function sl_updatePasscodeEnable(enabled) {
var l10nId = 'disabled';
if (this._lockscreenEnable) {
l10nId = enabled ?
'screenLock-enabled-with-passcode' :
'screenLock-enabled-with-no-passcode';
}
this._element.setAttribute('data-l10n-id', l10nId);
}
};
return function ctor_screen_lock_item(element) {
return new ScreenLockItem(element);
};
});

View file

@ -0,0 +1,133 @@
/**
* SimSecurityItem is manily used in Single Sim device because this would
* be integrated into Sim Manager > Sim Security in DSDS devices.
*
* @module SimSecurityItem
*/
define(function(require) {
'use strict';
var SIMSlotManager = require('shared/simslot_manager');
var AirplaneModeHelper = require('shared/airplane_mode_helper');
var SimSecurity = require('modules/sim_security');
function SimSecurityItem(element) {
this._element = element;
this._itemEnabled = false;
this._cardIndex = 0;
this._activeSlot = this._getActiveSlot();
this._boundUpdateUI = this._updateUI.bind(this);
// Note
// Because we can't rely on Gecko's oncardstatechange, we have to
// update UI based on our customized events.
SimSecurity.addEventListener('pin-enabled', () => {
this._boundUpdateUI();
});
SimSecurity.addEventListener('pin-disabled', () => {
this._boundUpdateUI();
});
}
SimSecurityItem.prototype = {
/**
* Set the current status of SimSecurityItem
*
* @access public
* @param {Boolean} enabled
* @memberOf SimSecurityItem
*/
set enabled(enabled) {
// 1. SimSecurityItem only shows up on Single SIM devices
// 2. If there is no activeSlot, it means we don't have to do anything
// 3. If internal variable is enabled and we still want to enable,
// we don't have to do anything and vice versa.
if (SIMSlotManager.isMultiSIM() ||
!this._activeSlot || enabled === this._itemEnabled) {
return;
}
this._itemEnabled = enabled;
if (this._itemEnabled) {
this._boundUpdateUI();
AirplaneModeHelper.addEventListener('statechange',
this._boundUpdateUI);
} else {
AirplaneModeHelper.removeEventListener('statechange',
this._boundUpdateUI);
}
},
/**
* Get the current status of SimSecurityItem
*
* @access public
* @memberOf SimSecurityItem
*/
get enabled() {
return this._itemEnabled;
},
/**
* This method is used to update UI based on statuses of SIM / APM
*
* @access private
* @memberOf SimSecurityItem
*/
_updateUI: function() {
var promise = new Promise((resolve) => {
AirplaneModeHelper.ready(() => {
// if disabled
this._element.style.fontStyle = 'italic';
// if APM is enabled
var airplaneModeStatus = AirplaneModeHelper.getStatus();
if (airplaneModeStatus === 'enabled') {
this._element.setAttribute('data-l10n-id', 'simCardNotReady');
return resolve();
}
var cardState = this._activeSlot.simCard.cardState;
switch(cardState) {
case null:
this._element.setAttribute('data-l10n-id', 'noSimCard');
return resolve();
case 'unknown':
this._element.setAttribute('data-l10n-id', 'unknownSimCardState');
return resolve();
}
// enabled instead
this._element.style.fontStyle = 'normal';
SimSecurity.getCardLock(this._cardIndex, 'pin').then((result) => {
var enabled = result.enabled;
this._element.setAttribute('data-l10n-id',
enabled ? 'enabled' : 'disabled');
return resolve();
});
});
});
return promise;
},
/**
* We use this to get active Sim slot.
*
* @access private
* @memberOf SimSecurityItem
*/
_getActiveSlot: function() {
var slot = SIMSlotManager.get(this._cardIndex);
if (slot && !slot.isAbsent()) {
return slot;
}
}
};
return function ctor_sim_security_item(element) {
return new SimSecurityItem(element);
};
});

View file

@ -0,0 +1,168 @@
define(function(require) {
'use strict';
var STKHelper = require('shared/stk_helper');
function STKItem(elements) {
this._elements = elements;
this.init();
}
STKItem.prototype.init = function() {
var iccLoaded = false;
var self = this;
function loadIccPage(callback) {
callback = (typeof callback === 'function') ? callback : function() {};
if (iccLoaded) {
return callback();
}
Settings.currentPanel = '#icc';
window.addEventListener('iccPageLoaded',
function oniccPageLoaded(event) {
iccLoaded = true;
callback();
});
}
function executeIccCmd(iccMessage) {
if (!iccMessage) {
return;
}
// Clear cache
var reqIccData = window.navigator.mozSettings.createLock().set({
'icc.data': null
});
reqIccData.onsuccess = function icc_getIccData() {
window.DUMP('ICC Cache cleared');
};
// Open ICC section
window.DUMP('ICC message to execute: ', iccMessage);
loadIccPage(function() {
var event = new CustomEvent('stkasynccommand', {
detail: { 'message': iccMessage }
});
window.dispatchEvent(event);
});
}
setTimeout(function updateStkMenu() {
window.DUMP('Showing STK main menu');
// XXX https://bugzilla.mozilla.org/show_bug.cgi?id=844727
// We should use Settings.settingsCache first
var settings = navigator.mozSettings;
var lock = settings.createLock();
function showStkEntries(menu) {
window.DUMP('STK cached menu: ', menu);
if (!menu || typeof menu !== 'object' ||
Object.keys(menu).length === 0) {
window.DUMP('No STK available - exit');
self._elements.iccMainHeader.hidden = true;
self._elements.iccEntries.hidden = true;
return;
}
// Clean current entries
self._elements.iccEntries.innerHTML = '';
self._elements.iccMainHeader.hidden = true;
self._elements.iccEntries.hidden = true;
// update and show the entry in settings
Object.keys(menu).forEach(function(SIMNumber) {
window.DUMP('STK Menu for SIM ' + SIMNumber +
' (' + menu[SIMNumber].iccId + ') - ', menu[SIMNumber].entries);
var li = document.createElement('li');
var a = document.createElement('a');
var menuItem = menu[SIMNumber].entries;
var icon = STKHelper.getFirstIconRawData(menuItem);
a.id = 'menuItem-icc-' + menu[SIMNumber].iccId;
a.className = 'menu-item menuItem-icc';
a.href = '#icc';
if (icon) {
var iconContainer = document.createElement('span');
iconContainer.appendChild(STKHelper.getIconCanvas(icon));
iconContainer.setAttribute('aria-hidden', true);
li.appendChild(iconContainer);
self._elements.iccEntries.dataset.customIcon = true;
} else {
a.dataset.icon = 'sim-toolkit';
}
a.onclick = function menu_icc_onclick() {
window.DUMP('Touched ' + menu[SIMNumber].iccId);
loadIccPage(function() {
var event = new CustomEvent('stkmenuselection', {
detail: { 'menu': menu[SIMNumber] }
});
window.dispatchEvent(event);
});
};
var span = document.createElement('span');
var title = menu[SIMNumber].entries.title;
span.textContent = title;
a.appendChild(span);
document.l10n.setAttributes(a, 'stkEntry', {title: title});
if (Object.keys(menu).length > 1) {
var small = document.createElement('small');
small.setAttribute('data-l10n-id', 'sim' + SIMNumber);
small.classList.add('menu-item-desc');
small.id = 'sim-desc-' + SIMNumber;
a.setAttribute('aria-describedby', small.id);
a.appendChild(small);
}
li.appendChild(a);
self._elements.iccEntries.appendChild(li);
self._elements.iccMainHeader.hidden = false;
self._elements.iccEntries.hidden = false;
});
}
// Check if SIM card sends an Applications menu
var reqApplications = lock.get('icc.applications');
reqApplications.onsuccess = function icc_getApplications() {
var json = reqApplications.result['icc.applications'];
var menu = json && JSON.parse(json);
showStkEntries(menu);
};
settings.addObserver('icc.applications',
function icc_getApplications(event) {
var json = event.settingValue;
var menu = json && JSON.parse(json);
window.DUMP('STK Settings.currentPanel ' + Settings.currentPanel);
if (Settings && Settings.currentPanel === '#icc') {
Settings.currentPanel = '#root';
}
showStkEntries(menu);
});
// Check if there are pending STK commands
var reqIccData = lock.get('icc.data');
reqIccData.onsuccess = function icc_getIccData() {
var cmd = reqIccData.result['icc.data'];
if (cmd) {
window.DUMP('ICC async command (launcher)');
executeIccCmd(JSON.parse(cmd));
}
};
settings.addObserver('icc.data', function(event) {
var value = event.settingValue;
if (value) {
window.DUMP('ICC async command while settings running: ', value);
executeIccCmd(JSON.parse(value));
}
});
}.bind(this));
};
return function ctor_stk_item(elements) {
return new STKItem(elements);
};
});

View file

@ -0,0 +1,71 @@
/**
* Links the root panel list item with AppStorage.
*/
define(function(require) {
'use strict';
var AppStorage = require('modules/app_storage');
var StorageHelper = require('modules/storage_helper');
/**
* @alias module:panels/root/storage_app_item
* @class AppStorageItem
* @requires module:modules/app_storage
* @param {HTMLElement} element
The element displaying the app storage information
* @returns {AppStorageItem}
*/
function AppStorageItem(element) {
this._enabled = false;
this._element = element;
this._boundUpdateAppFreeSpace = this._updateAppFreeSpace.bind(this);
}
AppStorageItem.prototype = {
/**
* The value indicates whether the module is responding. If it is false, the
* UI stops reflecting the updates from the root panel context.
*
* @access public
* @memberOf AppStorageItem.prototype
* @type {Boolean}
*/
get enabled() {
return this._enabled;
},
set enabled(value) {
if (this._enabled === value) {
return;
} else {
this._enabled = value;
}
if (value) { //observe
AppStorage.observe('freeSize', this._boundUpdateAppFreeSpace);
this._updateAppFreeSpace();
document.addEventListener('DOMRetranslated', this);
} else { //unobserve
AppStorage.unobserve('freeSize', this._boundUpdateAppFreeSpace);
document.removeEventListener('DOMRetranslated', this);
}
},
// Application Storage
_updateAppFreeSpace: function storage_updateAppFreeSpace() {
StorageHelper.showFormatedSize(this._element,
'availableSize', AppStorage.freeSize);
},
handleEvent: function storage_handleEvent(evt) {
switch (evt.type) {
case 'DOMRetranslated':
this._updateAppFreeSpace();
break;
}
}
};
return function ctor_app_storage_item(element) {
return new AppStorageItem(element);
};
});

View file

@ -0,0 +1,138 @@
/**
* Links the root panel list item with USB Mass Storage(UMS).
* Will disable Media Storage panel when UMS enabled.
*/
define(function(require) {
'use strict';
var SettingsListener = require('shared/settings_listener');
var MediaStorage = require('modules/media_storage');
var StorageHelper = require('modules/storage_helper');
var _debug = false;
var debug = function() {};
if (_debug) {
debug = function storage_debug(msg) {
console.log('--> [USBStorageItem]: ' + msg);
};
}
/**
* @alias module:panels/root/storage_usb_item
* @class USBStorageItem
* @param {Object} elements
elements displaying the usb and media storage information
* @returns {USBStorageItem}
*/
function USBStorageItem(elements) {
this._enabled = false;
this._elements = elements;
this._keyUmsEnabled = 'ums.enabled';
this._boundUmsEnabledHandler = this._umsEnabledHandler.bind(this);
this._boundUpdateVolumeState = this._updateVolumeState.bind(this);
}
USBStorageItem.prototype = {
/**
* The value indicates whether the module is responding. If it is false, the
* UI stops reflecting the updates from the root panel context.
*
* @access public
* @memberOf USBStorageItem.prototype
* @type {Boolean}
*/
get enabled() {
return this._enabled;
},
set enabled(value) {
if (this._enabled === value) {
return;
} else {
this._enabled = value;
}
if (value) { //observe
SettingsListener.observe(this._keyUmsEnabled, false,
this._boundUmsEnabledHandler);
MediaStorage.observe('volumeState', this._boundUpdateVolumeState);
MediaStorage.observe('freeSize', this._boundUpdateVolumeState);
document.addEventListener('DOMRetranslated', this);
} else { //unobserve
SettingsListener.unobserve(this._keyUmsEnabled,
this._boundUmsEnabledHandler);
MediaStorage.unobserve('volumeState', this._boundUpdateVolumeState);
MediaStorage.unobserve('freeSize', this._boundUpdateVolumeState);
document.removeEventListener('DOMRetranslated', this);
}
},
_umsEnabledHandler: function storage_umsEnabledHandler(enabled) {
debug('_umsEnabledHandler');
this._enabled = enabled;
this._updateUmsDesc();
},
handleEvent: function storage_handleEvent(evt) {
switch (evt.type) {
case 'DOMRetranslated':
this._updateVolumeState();
break;
}
},
// ums description
_updateUmsDesc: function storage_updateUmsDesc() {
var key;
debug('enabled:' + this._enabled + '/' +
'volumeState:' + MediaStorage.volumeState);
if (this._enabled) {
//TODO list all enabled volume name
key = 'enabled';
} else if (MediaStorage.volumeState === 'shared') {
key = 'umsUnplugToDisable';
} else {
key = 'disabled';
}
this._elements.usbEnabledInfoBlock.setAttribute('data-l10n-id', key);
},
_updateVolumeState: function storage_updateVolumeState() {
debug('_updateVolumeState');
this._updateUmsDesc();
switch (MediaStorage.volumeState) {
case 'available':
StorageHelper.showFormatedSize(this._elements.mediaStorageDesc,
'availableSize', MediaStorage.freeSize);
this._lockMediaStorageMenu(false);
break;
case 'shared':
this._elements.mediaStorageDesc.removeAttribute('data-l10n-id');
this._elements.mediaStorageDesc.textContent = '';
this._lockMediaStorageMenu(false);
break;
case 'unavailable':
this._elements.mediaStorageDesc.setAttribute('data-l10n-id',
'no-storage');
this._lockMediaStorageMenu(true);
break;
}
},
_lockMediaStorageMenu: function storage_setMediaMenuState(lock) {
if (lock) {
this._elements.mediaStorageSection.setAttribute('aria-disabled', true);
} else {
this._elements.mediaStorageSection.removeAttribute('aria-disabled');
}
}
};
return function ctor_usb_storage_item(elements) {
return new USBStorageItem(elements);
};
});

View file

@ -0,0 +1,116 @@
/**
* This module is used to show/hide themes menuItem based on the number of
* current installed themes.
*
* @module ThemesItem
*/
define(function(require) {
'use strict';
var AppsCache = require('modules/apps_cache');
function ThemesItem(element) {
this._enabled = false;
this._element = element;
this._themeCount = 0;
this._boundUpdateThemes = this._updateThemes.bind(this);
this.init();
}
ThemesItem.prototype = {
/**
* Set current status of themesItem
*
* @access public
* @param {Boolean} enabled
* @memberOf ThemesItem
*/
set enabled(enabled) {
if (this._enabled === enabled) {
return;
} else {
this._enabled = enabled;
if (this._enabled) {
this._updateThemeSectionVisibility();
}
}
},
/**
* Get current status of themesItem
*
* @access public
* @memberOf ThemesItem
*/
get enabled() {
return this._enabled;
},
/**
* Initialization
*
* @access private
* @memberOf ThemesItem
* @return {Promise}
*/
init: function() {
var self = this;
AppsCache.addEventListener('install', this._boundUpdateThemes);
AppsCache.addEventListener('uninstall', this._boundUpdateThemes);
return AppsCache.apps().then(function(apps) {
apps.some(function(app) {
if (self._isThemeApp(app)) {
self._themeCount += 1;
}
});
self._updateThemeSectionVisibility();
});
},
/**
* Check whether this app is theme app
*
* @param {Object} app
* @returns {Boolean}
* @memberOf ThemesItem
*/
_isThemeApp: function(app) {
var manifest = app.manifest || app.updateManifest;
return manifest.role === 'theme';
},
/**
* We have to update theme count based on incoming evt and
* decide to show/hide or not.
*
* @param {Object} evt
* @memberOf ThemesItem
*/
_updateThemes: function(evt) {
var app = evt && evt.application;
var type = evt.type;
if (this._isThemeApp(app)) {
if (type === 'install') {
this._themeCount += 1;
} else if (type === 'uninstall') {
this._themeCount -= 1;
}
this._updateThemeSectionVisibility();
}
},
/**
* Update theme section visibility based on _themeCount
*
* @memberOf ThemesItem
*/
_updateThemeSectionVisibility: function() {
this._element.hidden = (this._themeCount < 2);
}
};
return function ctor_themesItem(element) {
return new ThemesItem(element);
};
});

View file

@ -0,0 +1,49 @@
define(function(require) {
'use strict';
var WifiContext = require('modules/wifi_context');
function WifiItem(element) {
this._enabled = false;
this._boundUpdateWifiDesc = this._updateWifiDesc.bind(this, element);
}
WifiItem.prototype = {
set enabled(value) {
if (value === this._enabled || !navigator.mozWifiManager) {
return;
}
this._enabled = value;
if (this._enabled) {
this._boundUpdateWifiDesc();
WifiContext.addEventListener('wifiStatusTextChange',
this._boundUpdateWifiDesc);
} else {
WifiContext.removeEventListener('wifiStatusTextChange',
this._boundUpdateWifiDesc);
}
},
get enabled() {
return this._enabled;
},
_updateWifiDesc: function root_updateWifiDesc(element) {
element.setAttribute('data-l10n-id', WifiContext.wifiStatusText.id);
if (WifiContext.wifiStatusText.args) {
element.setAttribute('data-l10n-args',
JSON.stringify(WifiContext.wifiStatusText.args));
} else {
element.removeAttribute('data-l10n-args');
}
// Bug 1217717 enable the Airplane mode interaction
// once the wifi panel is ready
window.dispatchEvent(new CustomEvent('wificontext-ready'));
}
};
return function ctor_wifiItem(element) {
return new WifiItem(element);
};
});