/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Creates a "toggle control", which is a stylized checkbox with an icon. The // onToggleCb callback is called every time the control changes state with the // new toggle position (true for ON) and is expected to return a promise of the // new toggle position which can resolve to the opposite position of the one // received if there was error. function createToggleControl(elm, iconName, onToggleCb, initialState = false) { let icon = document.createElement('span'); icon.classList.add('toggle-control-icon'); icon.classList.add('material-icons-outlined'); if (iconName) { icon.appendChild(document.createTextNode(iconName)); } elm.appendChild(icon); let toggle = document.createElement('label'); toggle.classList.add('toggle-control-switch'); let input = document.createElement('input'); input.type = 'checkbox'; input.checked = !!initialState; input.onchange = e => { let nextPr = onToggleCb(e.target.checked); if (nextPr && 'then' in nextPr) { nextPr.then(checked => { e.target.checked = !!checked; }); } }; toggle.appendChild(input); let slider = document.createElement('span'); slider.classList.add('toggle-control-slider'); toggle.appendChild(slider); elm.classList.add('toggle-control'); elm.appendChild(toggle); return { // Sets the state of the toggle control. This only affects the // visible state of the control in the UI, it doesn't affect the // state of the underlying resources. It's most useful to make // changes of said resources visible to the user. Set: checked => input.checked = !!checked, }; } function createButtonListener(button_id_class, func, deviceConnection, listener) { let buttons = []; let ele = document.getElementById(button_id_class); if (ele != null) { buttons.push(ele); } else { buttons = document.getElementsByClassName(button_id_class); } for (var button of buttons) { if (func != null) { button.onclick = func; } button.addEventListener('mousedown', listener); } } function createInputListener(input_id, func, listener) { input = document.getElementById(input_id); if (func != null) { input.oninput = func; } input.addEventListener('input', listener); } function validateMacAddress(val) { var regex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/; return (regex.test(val)); } function validateMacWrapper() { let type = document.getElementById('bluetooth-wizard-type').value; let button = document.getElementById("bluetooth-wizard-device"); let macField = document.getElementById('bluetooth-wizard-mac'); if (this.id == 'bluetooth-wizard-type') { if (type == "remote_loopback") { button.disabled = false; macField.setCustomValidity(''); macField.disabled = true; macField.required = false; macField.placeholder = 'N/A'; macField.value = ''; return; } } macField.disabled = false; macField.required = true; macField.placeholder = 'Device MAC'; if (validateMacAddress($(macField).val())) { button.disabled = false; macField.setCustomValidity(''); } else { button.disabled = true; macField.setCustomValidity('MAC address invalid'); } } $('[validate-mac]').bind('input', validateMacWrapper); $('[validate-mac]').bind('select', validateMacWrapper); function parseDevice(device) { let id, name, mac; var regex = /([0-9]+):([^@ ]*)(@(([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})))?/; if (regex.test(device)) { let regexMatches = device.match(regex); id = regexMatches[1]; name = regexMatches[2]; mac = regexMatches[4]; } if (mac === undefined) { mac = ""; } return [id, name, mac]; } function btUpdateAdded(devices) { let deviceArr = devices.split('\r\n'); let [id, name, mac] = parseDevice(deviceArr[0]); if (name) { let div = document.getElementById('bluetooth-wizard-confirm').getElementsByClassName('bluetooth-text')[1]; div.innerHTML = ""; div.innerHTML += "
Name: " + id + "
"; div.innerHTML += "Type: " + name + "
"; div.innerHTML += "MAC Addr: " + mac + "
"; return true; } return false; } function parsePhy(phy) { let id = phy.substring(0, phy.indexOf(":")); phy = phy.substring(phy.indexOf(":") + 1); let name = phy.substring(0, phy.indexOf(":")); let devices = phy.substring(phy.indexOf(":") + 1); return [id, name, devices]; } function btParsePhys(phys) { if (phys.indexOf("Phys:") < 0) { return null; } let phyDict = {}; phys = phys.split('Phys:')[1]; let phyArr = phys.split('\r\n'); for (var phy of phyArr.slice(1)) { phy = phy.trim(); if (phy.length == 0 || phy.indexOf("deleted") >= 0) { continue; } let [id, name, devices] = parsePhy(phy); phyDict[name] = id; } return phyDict; } function btUpdateDeviceList(devices) { let deviceArr = devices.split('\r\n'); if (deviceArr[0].indexOf("Devices:") >= 0) { let div = document.getElementById('bluetooth-list').getElementsByClassName('bluetooth-text')[0]; div.innerHTML = ""; let count = 0; for (var device of deviceArr.slice(1)) { if (device.indexOf("Phys:") >= 0) { break; } count++; if (device.indexOf("deleted") >= 0) { continue; } let [id, name, mac] = parseDevice(device); let innerDiv = '