blob: 0eb291bae7474dc76ea2ba8030e407b9f718396d [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @implements {SDK.SDKModelObserver<!SDK.EmulationModel>}
*/
export class ThrottlingManager extends Common.Object {
constructor() {
super();
/** @type {!MobileThrottling.CPUThrottlingRates} */
this._cpuThrottlingRate = MobileThrottling.CPUThrottlingRates.NoThrottling;
/** @type {!Set<!UI.ToolbarComboBox>} */
this._cpuThrottlingControls = new Set();
this._cpuThrottlingRates = MobileThrottling.cpuThrottlingPresets;
/** @type {!Common.Setting<!Array<!SDK.NetworkManager.Conditions>>} */
this._customNetworkConditionsSetting = Common.moduleSetting('customNetworkConditions');
/** @type {!SDK.NetworkManager.Conditions} */
this._currentNetworkThrottlingConditions = SDK.NetworkManager.NoThrottlingConditions;
/** @type {!SDK.NetworkManager.Conditions} */
this._lastNetworkThrottlingConditions;
SDK.multitargetNetworkManager.addEventListener(SDK.MultitargetNetworkManager.Events.ConditionsChanged, () => {
this._lastNetworkThrottlingConditions = this._currentNetworkThrottlingConditions;
this._currentNetworkThrottlingConditions = SDK.multitargetNetworkManager.networkConditions();
});
SDK.targetManager.observeModels(SDK.EmulationModel, this);
}
/**
* @param {!HTMLSelectElement} selectElement
* @return {!MobileThrottling.NetworkThrottlingSelector}
*/
decorateSelectWithNetworkThrottling(selectElement) {
let options = [];
const selector =
new MobileThrottling.NetworkThrottlingSelector(populate, select, this._customNetworkConditionsSetting);
selectElement.addEventListener('change', optionSelected, false);
return selector;
/**
* @param {!Array.<!MobileThrottling.NetworkThrottlingConditionsGroup>} groups
* @return {!Array<?SDK.NetworkManager.Conditions>}
*/
function populate(groups) {
selectElement.removeChildren();
options = [];
for (let i = 0; i < groups.length; ++i) {
const group = groups[i];
const groupElement = selectElement.createChild('optgroup');
groupElement.label = group.title;
for (const conditions of group.items) {
const title = conditions.title;
const option = new Option(title, title);
UI.ARIAUtils.setAccessibleName(option, ls`${group.title}: ${title}`);
groupElement.appendChild(option);
options.push(conditions);
}
if (i === groups.length - 1) {
const option = new Option(ls`Add\u2026`, ls`Add\u2026`);
UI.ARIAUtils.setAccessibleName(option, ls`Add ${group.title}`);
groupElement.appendChild(option);
options.push(null);
}
}
return options;
}
function optionSelected() {
if (selectElement.selectedIndex === selectElement.options.length - 1) {
selector.revealAndUpdate();
} else {
selector.optionSelected(options[selectElement.selectedIndex]);
}
}
/**
* @param {number} index
*/
function select(index) {
if (selectElement.selectedIndex !== index) {
selectElement.selectedIndex = index;
}
}
}
/**
* @return {!UI.ToolbarCheckbox}
*/
createOfflineToolbarCheckbox() {
const checkbox = new UI.ToolbarCheckbox(
Common.UIString('Offline'), Common.UIString('Force disconnected from network'), forceOffline.bind(this));
SDK.multitargetNetworkManager.addEventListener(
SDK.MultitargetNetworkManager.Events.ConditionsChanged, networkConditionsChanged);
checkbox.setChecked(SDK.multitargetNetworkManager.networkConditions() === SDK.NetworkManager.OfflineConditions);
/**
* @this {!ThrottlingManager}
*/
function forceOffline() {
if (checkbox.checked()) {
SDK.multitargetNetworkManager.setNetworkConditions(SDK.NetworkManager.OfflineConditions);
} else {
SDK.multitargetNetworkManager.setNetworkConditions(this._lastNetworkThrottlingConditions);
}
}
function networkConditionsChanged() {
checkbox.setChecked(SDK.multitargetNetworkManager.networkConditions() === SDK.NetworkManager.OfflineConditions);
}
return checkbox;
}
/**
* @return {!UI.ToolbarMenuButton}
*/
createMobileThrottlingButton() {
const button = new UI.ToolbarMenuButton(appendItems);
button.setTitle(Common.UIString('Throttling'));
button.setGlyph('');
button.turnIntoSelect();
button.setDarkText();
/** @type {!MobileThrottling.ConditionsList} */
let options = [];
let selectedIndex = -1;
const selector = new MobileThrottling.MobileThrottlingSelector(populate, select);
return button;
/**
* @param {!UI.ContextMenu} contextMenu
*/
function appendItems(contextMenu) {
for (let index = 0; index < options.length; ++index) {
const conditions = options[index];
if (!conditions) {
continue;
}
if (conditions.title === MobileThrottling.CustomConditions.title &&
conditions.description === MobileThrottling.CustomConditions.description) {
continue;
}
contextMenu.defaultSection().appendCheckboxItem(
Common.UIString(conditions.title),
selector.optionSelected.bind(selector, /** @type {!MobileThrottling.Conditions} */ (conditions)),
selectedIndex === index);
}
}
/**
* @param {!Array.<!MobileThrottling.MobileThrottlingConditionsGroup>} groups
* @return {!MobileThrottling.ConditionsList}
*/
function populate(groups) {
options = [];
for (const group of groups) {
for (const conditions of group.items) {
options.push(conditions);
}
options.push(null);
}
return options;
}
/**
* @param {number} index
*/
function select(index) {
selectedIndex = index;
button.setText(options[index].title);
button.setTitle(options[index].description);
}
}
/**
* @return {number}
*/
cpuThrottlingRate() {
return this._cpuThrottlingRate;
}
/**
* @param {!MobileThrottling.CPUThrottlingRates} rate
*/
setCPUThrottlingRate(rate) {
this._cpuThrottlingRate = rate;
for (const emulationModel of SDK.targetManager.models(SDK.EmulationModel)) {
emulationModel.setCPUThrottlingRate(this._cpuThrottlingRate);
}
let icon = null;
if (this._cpuThrottlingRate !== MobileThrottling.CPUThrottlingRates.NoThrottling) {
Host.userMetrics.actionTaken(Host.UserMetrics.Action.CpuThrottlingEnabled);
icon = UI.Icon.create('smallicon-warning');
icon.title = Common.UIString('CPU throttling is enabled');
}
const index = this._cpuThrottlingRates.indexOf(this._cpuThrottlingRate);
for (const control of this._cpuThrottlingControls) {
control.setSelectedIndex(index);
}
UI.inspectorView.setPanelIcon('timeline', icon);
this.dispatchEventToListeners(Events.RateChanged, this._cpuThrottlingRate);
}
/**
* @override
* @param {!SDK.EmulationModel} emulationModel
*/
modelAdded(emulationModel) {
if (this._cpuThrottlingRate !== MobileThrottling.CPUThrottlingRates.NoThrottling) {
emulationModel.setCPUThrottlingRate(this._cpuThrottlingRate);
}
}
/**
* @override
* @param {!SDK.EmulationModel} emulationModel
*/
modelRemoved(emulationModel) {
}
/**
* @return {!UI.ToolbarComboBox}
*/
createCPUThrottlingSelector() {
const control = new UI.ToolbarComboBox(
event => this.setCPUThrottlingRate(this._cpuThrottlingRates[event.target.selectedIndex]), ls`CPU throttling`);
this._cpuThrottlingControls.add(control);
const currentRate = this._cpuThrottlingRate;
for (let i = 0; i < this._cpuThrottlingRates.length; ++i) {
const rate = this._cpuThrottlingRates[i];
const title = rate === 1 ? Common.UIString('No throttling') : Common.UIString('%d\xD7 slowdown', rate);
const option = control.createOption(title);
control.addOption(option);
if (currentRate === rate) {
control.setSelectedIndex(i);
}
}
return control;
}
}
/** @enum {symbol} */
export const Events = {
RateChanged: Symbol('RateChanged')
};
/**
* @implements {UI.ActionDelegate}
*/
export class ActionDelegate {
/**
* @override
* @param {!UI.Context} context
* @param {string} actionId
* @return {boolean}
*/
handleAction(context, actionId) {
if (actionId === 'network-conditions.network-online') {
SDK.multitargetNetworkManager.setNetworkConditions(SDK.NetworkManager.NoThrottlingConditions);
return true;
}
if (actionId === 'network-conditions.network-low-end-mobile') {
SDK.multitargetNetworkManager.setNetworkConditions(SDK.NetworkManager.Slow3GConditions);
return true;
}
if (actionId === 'network-conditions.network-mid-tier-mobile') {
SDK.multitargetNetworkManager.setNetworkConditions(SDK.NetworkManager.Fast3GConditions);
return true;
}
if (actionId === 'network-conditions.network-offline') {
SDK.multitargetNetworkManager.setNetworkConditions(SDK.NetworkManager.OfflineConditions);
return true;
}
return false;
}
}
/**
* @return {!ThrottlingManager}
*/
export function throttlingManager() {
return self.singleton(ThrottlingManager);
}
/* Legacy exported object */
self.MobileThrottling = self.MobileThrottling || {};
/* Legacy exported object */
MobileThrottling = MobileThrottling || {};
/** @constructor */
MobileThrottling.ThrottlingManager = ThrottlingManager;
MobileThrottling.ThrottlingManager.Events = Events;
/** @constructor */
MobileThrottling.ThrottlingManager.ActionDelegate = ActionDelegate;
MobileThrottling.throttlingManager = throttlingManager;