VulpesOS/gaia/apps/settings/js/panels/icc/icc.js
OverSu b38dea0597 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.
2026-09-30 23:13:03 +02:00

544 lines
17 KiB
JavaScript
Executable file

require([
'shared/stk_helper'
], function(STKHelper) {
'use strict';
(function() {
var iccManager = window.navigator.mozIccManager;
function getIcc(iccId) {
window.DUMP('ICC Getting ICC for ' + iccId);
return iccManager.getIccById(iccId);
}
/**
* Move settings to foreground
*/
function reopenSettings() {
navigator.mozApps.getSelf().onsuccess = function getSelfCB(evt) {
var app = evt.target.result;
app.launch('settings');
};
}
// Consts
// 3GPP spec: TS 11.14
// 13.4 Type of Command and Next Action Indicator
const STK_NEXT_ACTION_INDICATOR = {
16: 'stkItemsNaiSetUpCall',
17: 'stkItemsNaiSendSs',
18: 'stkItemsNaiSendUssd',
19: 'stkItemsNaiSendSms',
32: 'stkItemsNaiPlayTone',
33: 'stkItemsNaiDisplayText',
34: 'stkItemsNaiGetInkey',
35: 'stkItemsNaiGetInput',
36: 'stkItemsNaiSelectItem',
37: 'stkItemsNaiSetUpMenu',
40: 'stkItemsNaiSetIdleModeText',
48: 'stkItemsNaiPerformCardApdu', // class "a"
49: 'stkItemsNaiPowerOnCard', // class "a"
50: 'stkItemsNaiPowerOffCard', // class "a"
51: 'stkItemsNaiGetReaderStatus', // class "a"
64: 'stkItemsNaiOpenChannel', // class "e"
65: 'stkItemsNaiCloseChannel', // class "e"
66: 'stkItemsNaiReceiveData', // class "e"
67: 'stkItemsNaiSendData', // class "e"
68: 'stkItemsNaiGetChannelStatus', // class "e"
96: 'Reserved', // for TIA/EIA-136
129: 'stkItemsNaiEndOfTheProactiveSession'
};
/**
* Init
*/
var iccStkList = document.getElementById('icc-stk-list');
var iccStkMainHeader = document.getElementById('icc-stk-main-header');
var iccStkHeader = document.getElementById('icc-stk-header');
var iccStkSubheader = document.getElementById('icc-stk-subheader');
var stkOpenAppName = null;
var stkLastSelectedText = null;
var goBackTimer = {
timer: null,
timeout: 0
};
var selectTimer = {
timer: null,
timeout: 0
};
var _visibilityChangeHandler = null;
var _backHandler = null;
init();
/**
* This is a helper for localizing DOM Elements using L10nID.
* Second argument may take one of the following forms:
* a string -> l10nId
* an object -> {id: l10nId, args: l10nArgs}
* an object -> {raw: string}
*
* Read more at MDN: http://mzl.la/1A76Fby
*/
function localizeElement(element, l10n) {
if (typeof(l10n) === 'string') {
element.setAttribute('data-l10n-id', l10n);
} else if (l10n.raw) {
element.removeAttribute('data-l10n-id');
element.textContent = l10n.raw;
} else {
document.l10n.setAttributes(element, l10n.id, l10n.attrs);
}
}
function sendVisibilityChangeEvent() {
navigator.mozApps.getSelf().onsuccess = function(evt) {
var app = evt.target.result;
app.connect('settingsstk').then(function onConnAccepted(ports) {
window.DUMP('STK_Settings IAC: ' + ports);
ports.forEach(function(port) {
window.DUMP('STK_Settings IAC: ' + port);
port.postMessage('StkMenuHidden');
});
}, function onConnRejected(reason) {
window.DUMP('STK_Settings IAC is rejected');
window.DUMP(reason);
});
};
}
function getNextActionString(nextActionList, index) {
window.DUMP('STK NAL: ' + nextActionList);
var nextActionString;
if (nextActionList &&
nextActionList[index] !== null &&
nextActionList[index] !== 96 &&
STK_NEXT_ACTION_INDICATOR[nextActionList[index]]) {
nextActionString = STK_NEXT_ACTION_INDICATOR[nextActionList[index]];
} else {
nextActionString = null;
}
return nextActionString;
}
function visibilityChangeHandler() {
if (document.hidden && Settings && Settings.currentPanel == '#icc') {
window.DUMP('STK_Settings visibilityChangeHandler');
sendVisibilityChangeEvent();
}
}
/**
* Init STK UI
*/
function init() {
window.addEventListener('stkasynccommand',
function do_handleAsyncSTKCmd(event) {
handleSTKMessage(event.detail.message);
});
window.addEventListener('stkmenuselection',
function do_handleAsyncSTKCmd(event) {
updateMenu(event.detail.menu);
});
document.addEventListener('visibilitychange',
visibilityChangeHandler, false);
iccStkMainHeader.addEventListener('action', function onBack() {
if (typeof _backHandler === 'function') {
_backHandler();
}
});
}
function addCloseNotificationsEvents(message) {
function onVisibilityChange() {
if (document.hidden && Settings && Settings.currentPanel == '#icc') {
document.removeEventListener('visibilitychange',
_visibilityChangeHandler, false);
stkResTerminate(message);
}
}
document.removeEventListener('visibilitychange',
_visibilityChangeHandler, false);
_visibilityChangeHandler = onVisibilityChange;
document.addEventListener('visibilitychange',
_visibilityChangeHandler, false);
window.onbeforeunload = function() {
responseSTKCommand(message, {
resultCode: iccManager.STK_RESULT_NO_RESPONSE_FROM_USER
}, true);
};
}
function returnToSettingsMainMenu() {
if (Settings) {
Settings.currentPanel = '#root';
}
}
function stkResTerminate(message) {
returnToSettingsMainMenu();
responseSTKCommand(message, {
resultCode: iccManager.STK_RESULT_UICC_SESSION_TERM_BY_USER
}, true);
}
function stkResGoBack(message) {
responseSTKCommand(message, {
resultCode: iccManager.STK_RESULT_BACKWARD_MOVE_BY_USER
});
// We'll return to settings if no STK response received in a grace period
var reqTimerGoBack =
window.navigator.mozSettings.createLock().get('icc.goBackTimeout');
reqTimerGoBack.onsuccess = function icc_getTimerGoBackSuccess() {
goBackTimer.timeout = reqTimerGoBack.result['icc.goBackTimeout'];
goBackTimer.timer = setTimeout(function() {
returnToSettingsMainMenu();
}, goBackTimer.timeout);
};
}
function stkResNoResponse(message) {
var reqTimerSelect =
window.navigator.mozSettings.createLock().get('icc.selectTimeout');
reqTimerSelect.onsuccess = function icc_getTimerSelectSuccess() {
selectTimer.timeout = reqTimerSelect.result['icc.selectTimeout'];
selectTimer.timer = setTimeout(function() {
responseSTKCommand(message, {
resultCode: iccManager.STK_RESULT_NO_RESPONSE_FROM_USER
}, true);
returnToSettingsMainMenu();
}, selectTimer.timeout);
};
}
function stkCancelGoBack() {
if (goBackTimer.timer) {
window.clearTimeout(goBackTimer.timer);
goBackTimer.timer = null;
}
if (selectTimer.timer) {
window.clearTimeout(selectTimer.timer);
selectTimer.timer = null;
}
}
/**
* Response ICC Command
*/
function responseSTKCommand(message, response) {
window.DUMP('sendStkResponse to message: ', message);
window.DUMP('sendStkResponse -- # response = ', response);
getIcc(message.iccId).sendStkResponse(message.command, response);
}
/**
* Handle ICC Messages
*/
function handleSTKMessage(message) {
window.DUMP('STK Proactive Message:', message);
stkCancelGoBack();
reopenSettings();
switch (message.command.typeOfCommand) {
case iccManager.STK_CMD_SELECT_ITEM:
addCloseNotificationsEvents(message);
updateSelection(message);
Settings.currentPanel = '#icc';
_backHandler = stkResGoBack.bind(null, message);
break;
default:
window.DUMP('STK Message not managed... response OK');
responseSTKCommand(message, {
resultCode: iccManager.STK_RESULT_OK
});
}
}
/**
* Navigate through all available STK applications
*/
function updateMenu(menu) {
window.DUMP('Showing STK main menu: ', menu);
stkOpenAppName = null;
stkCancelGoBack();
clearList();
if (!menu || !menu.entries || !menu.entries.items ||
(menu.entries.items.length == 1 && menu.entries.items[0] === null)) {
return;
}
window.DUMP('STK Main App Menu title: ' + menu.entries.title);
window.DUMP('STK Main App Menu default item: ' +
menu.entries.defaultItem);
showTitle({raw: menu.entries.title});
menu.entries.items.forEach(function(menuItem, index) {
window.DUMP('STK Main App Menu item: ' + menuItem.text + ' # ' +
menuItem.identifier);
var nextActionString = getNextActionString(menu.entries.nextActionList,
index);
// Get the first icon if exists
var icon = STKHelper.getFirstIconRawData(menuItem);
if (icon) {
iccStkList.dataset.customIcon = true;
}
window.DUMP('STK NEXTACTION: ' + nextActionString);
iccStkList.appendChild(buildMenuEntry({
id: 'stk-menuitem-' + menuItem.identifier,
icon: icon,
text: {raw: menuItem.text},
nai: nextActionString,
onclick: onMainMenuItemClick,
attributes: [
['stk-menu-item-identifier', menuItem.identifier],
['stk-menu-item-iccId', menu.iccId]
]
}));
});
// Optional Help menu
if (menu.entries.isHelpAvailable) {
iccStkList.appendChild(buildMenuEntry({
id: 'stk-helpmenuitem',
text: 'operatorServices-helpmenu',
onclick: function __onHelpClick__(event) {
showHelpMenu(menu, event);
},
attributes: []
}));
}
getIcc(menu.iccId).onstksessionend = function handleSTKSessionEnd(event) {
updateMenu(menu);
Settings.currentPanel = '#icc';
};
_backHandler = function backToRootPanel() {
Settings.currentPanel = '#root';
};
}
function onMainMenuItemClick(event) {
var iccId = event.target.getAttribute('stk-menu-item-iccId');
var identifier = event.target.getAttribute('stk-menu-item-identifier');
window.DUMP('sendStkMenuSelection: ', identifier);
getIcc(iccId).sendStkMenuSelection(identifier, false);
stkLastSelectedText = event.target.textContent;
stkOpenAppName = stkLastSelectedText;
}
function showHelpMenu(menu, event) {
window.DUMP('Showing STK help menu');
stkOpenAppName = null;
clearList();
showTitle('operatorServices-helpmenu');
menu.entries.items.forEach(function(menuItem) {
window.DUMP('STK Main App Help item: ' + menuItem.text + ' # ' +
menuItem.identifier);
var icon = STKHelper.getFirstIconRawData(menuItem);
if (icon) {
iccStkList.dataset.customIcon = true;
}
iccStkList.appendChild(buildMenuEntry({
id: 'stk-helpitem-' + menuItem.identifier,
text: {raw: menuItem.text},
icon: icon,
onclick: onMainMenuHelpItemClick,
attributes: [
['stk-help-item-identifier', menuItem.identifier],
['stk-menu-item-iccId', menu.iccId]
]
}));
});
_backHandler = updateMenu.bind(null, menu);
}
function onMainMenuHelpItemClick(event) {
var iccId = event.target.getAttribute('stk-menu-item-iccId');
var identifier = event.target.getAttribute('stk-help-item-identifier');
window.DUMP('sendStkHelpMenuSelection: ', identifier);
getIcc(iccId).sendStkMenuSelection(identifier, true);
stkLastSelectedText = event.target.textContent;
stkOpenAppName = stkLastSelectedText;
}
/**
* Navigate through the STK application options
*/
function updateSelection(message) {
var menu = message.command.options;
window.DUMP('Showing STK menu');
clearList();
window.DUMP('STK App Menu title: ' + menu.title);
window.DUMP('STK App Menu default item: ' + menu.defaultItem);
showTitle({raw: menu.title});
menu.items.forEach(function(menuItem, index) {
window.DUMP('STK App Menu item: ' + menuItem.text + ' # ' +
menuItem.identifier);
var nextActionString = getNextActionString(menu.nextActionList, index);
window.DUMP('STK NEXTACTION: ' + nextActionString);
var icon = STKHelper.getFirstIconRawData(menuItem);
if (icon) {
iccStkList.dataset.customIcon = true;
}
iccStkList.appendChild(buildMenuEntry({
id: 'stk-menuitem-' + menuItem.identifier,
text: {raw: menuItem.text},
icon: icon,
nai: nextActionString,
onclick: function onSelectOptionClick(event) {
document.removeEventListener('visibilitychange',
_visibilityChangeHandler, false);
onSelectOption(message, event);
},
attributes: [['stk-select-option-identifier', menuItem.identifier]]
}));
});
// Optional Help menu
if (menu.isHelpAvailable) {
iccStkList.appendChild(buildMenuEntry({
id: 'stk-helpmenuitem',
text: 'operatorServices-helpmenu',
onclick: function __onHelpClick__(event) {
showHelpSelection(message, event);
},
attributes: []
}));
}
stkResNoResponse(message);
}
function onSelectOption(message, event) {
var identifier =
event.target.getAttribute('stk-select-option-identifier');
responseSTKCommand(message, {
resultCode: iccManager.STK_RESULT_OK,
itemIdentifier: identifier
});
stkLastSelectedText = event.target.textContent;
}
function showHelpSelection(message, event) {
var menu = message.command.options;
window.DUMP('Showing STK help menu');
stkOpenAppName = null;
clearList();
showTitle('operatorServices-helpmenu');
menu.items.forEach(function(menuItem) {
window.DUMP('STK Main App Help item: ' + menuItem.text + ' # ' +
menuItem.identifier);
var icon = STKHelper.getFirstIconRawData(menuItem);
if (icon) {
iccStkList.dataset.customIcon = true;
}
iccStkList.appendChild(buildMenuEntry({
id: 'stk-helpitem-' + menuItem.identifier,
text: {raw: menuItem.text},
icon: icon,
onclick: function onSelectOptionClick(event) {
onSelectionHelpItemClick(message, event);
},
attributes: [
['stk-help-item-identifier', menuItem.identifier],
['stk-menu-item-iccId', menu.iccId]
]
}));
});
_backHandler = updateSelection.bind(null, message);
}
function onSelectionHelpItemClick(message, event) {
var identifier = event.target.getAttribute('stk-help-item-identifier');
window.DUMP('sendStkHelpMenuSelection: ', identifier);
responseSTKCommand(message, {
resultCode: iccManager.STK_RESULT_HELP_INFO_REQUIRED,
itemIdentifier: identifier
});
stkLastSelectedText = event.target.textContent;
}
/**
* Auxiliar methods
*/
function showTitle(titleL10n) {
// If the application is automatically opened (no come from main menu)
if (!stkOpenAppName) {
stkOpenAppName = titleL10n;
}
localizeElement(iccStkHeader, stkOpenAppName);
// Show section
if (stkOpenAppName != titleL10n) {
localizeElement(iccStkSubheader, titleL10n);
iccStkSubheader.parentNode.classList.remove('hiddenheader');
iccStkSubheader.classList.remove('hidden');
} else {
localizeElement(iccStkSubheader, {raw: ''});
iccStkSubheader.parentNode.classList.add('hiddenheader');
iccStkSubheader.classList.add('hidden');
}
}
function clearList() {
while (iccStkList.hasChildNodes()) {
iccStkList.removeChild(iccStkList.lastChild);
}
}
function buildMenuEntry(entry) {
var li = document.createElement('li');
if (entry.nai) {
var small = document.createElement('small');
localizeElement(small, entry.nai);
li.appendChild(small);
}
if (entry.icon) {
var iconContainer = document.createElement('span');
iconContainer.appendChild(STKHelper.getIconCanvas(entry.icon));
li.appendChild(iconContainer);
}
var a = document.createElement('a');
a.id = entry.id;
entry.attributes.forEach(function attrIterator(attr) {
a.setAttribute(attr[0], attr[1]);
});
localizeElement(a, entry.text);
a.onclick = entry.onclick;
a.href = '#icc';
li.appendChild(a);
return li;
}
})();
window.dispatchEvent(new CustomEvent('iccPageLoaded', {
detail: {}
}));
});