• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { BaseElement, element } from '../../base-ui/BaseElement';
17import { SpFlagHtml } from './SpFlag.html';
18
19@element('sp-flags')
20export class SpFlags extends BaseElement {
21  private bodyEl: HTMLElement | undefined | null;
22
23  initElements(): void {
24    let parentElement = this.parentNode as HTMLElement;
25    parentElement.style.overflow = 'hidden';
26    this.bodyEl = this.shadowRoot?.querySelector('.body');
27    this.initConfigList();
28  }
29
30  initHtml(): string {
31    return SpFlagHtml;
32  }
33
34  private createConfigDiv(): HTMLDivElement {
35    let configDiv = document.createElement('div');
36    configDiv.className = 'flag-widget';
37    return configDiv;
38  }
39
40  private createCustomDiv(config: FlagConfigItem, configDiv: HTMLDivElement): void {
41    let configHadDiv = document.createElement('div');
42    configHadDiv.className = 'flag-head-div';
43    let titleLabel = document.createElement('label');
44    titleLabel.textContent = config.title;
45    titleLabel.className = 'flag-title-label';
46    let configSelect = document.createElement('select');
47    configSelect.className = 'flag-select';
48    configSelect.setAttribute('title', config.title);
49    config.switchOptions.forEach((optionItem) => {
50      let configOption = document.createElement('option');
51      configOption.value = optionItem.option;
52      configOption.textContent = optionItem.option;
53      if (optionItem.selected) {
54        configOption.selected = true;
55      }
56      configSelect.appendChild(configOption);
57    });
58    configSelect.addEventListener('change', () => {
59      let title = configSelect.getAttribute('title');
60      FlagsConfig.updateFlagsConfig(title!, configSelect.selectedOptions[0].value);
61      if (title === 'VSync' && configSelect.selectedOptions[0].value === 'Enabled') {
62        let vsyncSelect = this.shadowRoot?.querySelector('#vsyncSelect');
63        vsyncSelect?.removeAttribute('disabled');
64      }
65      if (title === 'VSync' && configSelect.selectedOptions[0].value === 'Disabled') {
66        let vsyncSelect = this.shadowRoot?.querySelector('#vsyncSelect');
67        vsyncSelect?.childNodes.forEach((child: ChildNode) => {
68          let selectEl = child as HTMLOptionElement;
69          if (child.textContent === 'VsyncGenerator') {
70            selectEl.selected = true;
71            FlagsConfig.updateFlagsConfig('vsyncValue', selectEl.value);
72          } else {
73            selectEl.selected = false;
74          }
75        });
76
77        vsyncSelect?.setAttribute('disabled', 'disabled');
78      }
79    });
80    let description = document.createElement('div');
81    description.className = 'flag-des-div';
82    description.textContent = config.describeContent;
83    configHadDiv.appendChild(titleLabel);
84    configHadDiv.appendChild(configSelect);
85    configDiv.appendChild(configHadDiv);
86    configDiv.appendChild(description);
87  }
88
89  private initConfigList(): void {
90    let allConfig = FlagsConfig.getAllFlagConfig();
91    allConfig.forEach((config) => {
92      let configDiv = this.createConfigDiv();
93      this.createCustomDiv(config, configDiv);
94      if (config.title === 'AnimationAnalysis') {
95        let configFooterDiv = document.createElement('div');
96        configFooterDiv.className = 'config_footer';
97        let deviceWidthLabelEl = document.createElement('label');
98        deviceWidthLabelEl.className = 'device_label';
99        deviceWidthLabelEl.textContent = 'PhysicalWidth :';
100        let deviceWidthEl = document.createElement('input');
101        deviceWidthEl.value = <string>config.addInfo!.physicalWidth;
102        deviceWidthEl.addEventListener('keyup', () => {
103          deviceWidthEl.value = deviceWidthEl.value.replace(/\D/g, '');
104        });
105        deviceWidthEl.addEventListener('blur', () => {
106          if (deviceWidthEl.value !== '') {
107            FlagsConfig.updateFlagsConfig('physicalWidth', Number(deviceWidthEl.value));
108          }
109        });
110        deviceWidthEl.className = 'device_input';
111        let deviceHeightLabelEl = document.createElement('label');
112        deviceHeightLabelEl.textContent = 'PhysicalHeight :';
113        deviceHeightLabelEl.className = 'device_label';
114        let deviceHeightEl = document.createElement('input');
115        deviceHeightEl.className = 'device_input';
116        deviceHeightEl.value = <string>config.addInfo!.physicalHeight;
117        deviceHeightEl.addEventListener('keyup', () => {
118          deviceHeightEl.value = deviceHeightEl.value.replace(/\D/g, '');
119        });
120        deviceHeightEl.addEventListener('blur', () => {
121          if (deviceWidthEl.value !== '') {
122            FlagsConfig.updateFlagsConfig('physicalHeight', Number(deviceHeightEl.value));
123          }
124        });
125        configFooterDiv.appendChild(deviceWidthLabelEl);
126        configFooterDiv.appendChild(deviceWidthEl);
127        configFooterDiv.appendChild(deviceHeightLabelEl);
128        configFooterDiv.appendChild(deviceHeightEl);
129        configDiv.appendChild(configFooterDiv);
130      }
131
132      if (config.title === 'VSync') {
133        let configFooterDiv = this.createVsyncOption();
134        configDiv.appendChild(configFooterDiv);
135      }
136
137      this.bodyEl!.appendChild(configDiv);
138    });
139  }
140
141  private createVsyncOption(): HTMLDivElement {
142    let configFooterDiv = document.createElement('div');
143    configFooterDiv.className = 'config_footer';
144    let vsyncLableEl = document.createElement('lable');
145    vsyncLableEl.className = 'vsync_lable';
146    let vsyncTypeEl = document.createElement('select');
147    vsyncTypeEl.setAttribute('id', 'vsyncSelect');
148    vsyncTypeEl.className = 'flag-select';
149    let vsyncGenOption = document.createElement('option'); // VsyncGeneratior = H:VsyncGenerator
150    vsyncGenOption.value = 'H:VsyncGenerator';
151    vsyncGenOption.textContent = 'VsyncGenerator';
152    vsyncGenOption.selected = true;
153    vsyncTypeEl.appendChild(vsyncGenOption);
154
155    let vsyncRsOption = document.createElement('option'); // Vsync-rs = H:rs_SendVsync
156    vsyncRsOption.value = 'H:rs_SendVsync';
157    vsyncRsOption.textContent = 'Vsync-rs';
158    vsyncTypeEl.appendChild(vsyncRsOption);
159
160    let vsyncAppOption = document.createElement('option'); // Vsync-app = H:app_SendVsync
161    vsyncAppOption.value = 'H:app_SendVsync';
162    vsyncAppOption.textContent = 'Vsync-app';
163    vsyncTypeEl.appendChild(vsyncAppOption);
164
165    FlagsConfig.updateFlagsConfig('vsyncValue', vsyncGenOption.value);
166    vsyncTypeEl.addEventListener('change', function () {
167      let selectValue = this.selectedOptions[0].value;
168      console.log(this);
169      console.log(this.selectedOptions[0]);
170      console.log(this.selectedOptions[0].value);
171      FlagsConfig.updateFlagsConfig('vsyncValue', selectValue);
172    });
173
174    let flagsItem = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY);
175    let flagsItemJson = JSON.parse(flagsItem!);
176    let vsync = flagsItemJson.VSync;
177    if (vsync === 'Enabled') {
178      vsyncTypeEl.removeAttribute('disabled');
179    } else {
180      vsyncTypeEl.setAttribute('disabled', 'disabled');
181      FlagsConfig.updateFlagsConfig('vsyncValue', vsyncGenOption.value);
182    }
183    configFooterDiv.appendChild(vsyncLableEl);
184    configFooterDiv.appendChild(vsyncTypeEl);
185    return configFooterDiv;
186  }
187}
188
189export type Params = {
190  [key: string]: unknown;
191};
192
193export class FlagsConfig {
194  static FLAGS_CONFIG_KEY = 'FlagsConfig';
195  static DEFAULT_CONFIG: Array<FlagConfigItem> = [
196    {
197      title: 'TaskPool',
198      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
199      describeContent: 'Analyze TaskPool templates',
200    },
201    {
202      title: 'AnimationAnalysis',
203      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
204      describeContent: 'Analyze Animation effect templates',
205      addInfo: { physicalWidth: 0, physicalHeight: 0 },
206    },
207    {
208      title: 'AppStartup',
209      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
210      describeContent: 'App Startup templates',
211    },
212    {
213      title: 'SchedulingAnalysis',
214      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
215      describeContent: 'Scheduling analysis templates',
216    },
217    {
218      title: 'BinderRunnable',
219      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
220      describeContent: 'support Cpu State Binder-Runnable',
221    },
222    {
223      title: 'FfrtConvert',
224      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
225      describeContent: 'Ffrt Convert templates',
226    },
227    {
228      title: 'Bpftrace',
229      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
230      describeContent: '',
231    },
232    {
233      title: 'HMKernel',
234      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
235      describeContent: '',
236    },
237    {
238      title: 'VSync',
239      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
240      describeContent: 'VSync Signal drawing',
241    },
242    {
243      title: 'LTPO',
244      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
245      describeContent: 'Lost Frame and HitchTime templates',
246    },
247  ];
248
249  static getAllFlagConfig(): Array<FlagConfigItem> {
250    let flagsConfigStr = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY);
251    if (flagsConfigStr === null) {
252      let flagConfigObj: Params = {};
253      FlagsConfig.DEFAULT_CONFIG.forEach((config) => {
254        let selectedOption = config.switchOptions.filter((option) => {
255          return option.selected;
256        });
257        let value = config.switchOptions[0].option;
258        if (selectedOption[0] !== undefined) {
259          value = selectedOption[0].option;
260        }
261        flagConfigObj[config.title] = value;
262        if (config.addInfo) {
263          for (const [key, value] of Object.entries(config.addInfo)) {
264            flagConfigObj[key] = value;
265          }
266        }
267      });
268      window.localStorage.setItem(FlagsConfig.FLAGS_CONFIG_KEY, JSON.stringify(flagConfigObj));
269      return FlagsConfig.DEFAULT_CONFIG;
270    } else {
271      let flagsConfig = JSON.parse(flagsConfigStr);
272      FlagsConfig.DEFAULT_CONFIG.forEach((config) => {
273        let cfg = flagsConfig[config.title];
274        if (cfg) {
275          config.switchOptions.forEach((option) => {
276            if (option.option === cfg) {
277              option.selected = true;
278            } else {
279              option.selected = false;
280            }
281          });
282        }
283        if (config.addInfo) {
284          for (const [key, value] of Object.entries(config.addInfo)) {
285            let cfg = flagsConfig[key];
286            if (cfg) {
287              config.addInfo[key] = cfg;
288            }
289          }
290        }
291      });
292    }
293    return FlagsConfig.DEFAULT_CONFIG;
294  }
295
296  static getSpTraceStreamParseConfig(): string {
297    let parseConfig = {};
298    FlagsConfig.getAllFlagConfig().forEach((configItem) => {
299      let selectedOption = configItem.switchOptions.filter((option) => {
300        return option.selected;
301      });
302      // @ts-ignore
303      parseConfig[configItem.title] = selectedOption[0].option === 'Enabled' ? 1 : 0;
304    });
305    return JSON.stringify({ config: parseConfig });
306  }
307
308  static getFlagsConfig(flagName: string): Params | undefined {
309    let flagConfigObj: Params = {};
310    let configItem = FlagsConfig.getAllFlagConfig().find((config) => {
311      return config.title === flagName;
312    });
313    if (configItem) {
314      let selectedOption = configItem.switchOptions.filter((option) => {
315        return option.selected;
316      });
317      let value = configItem.switchOptions[0].option;
318      if (selectedOption[0] !== undefined) {
319        value = selectedOption[0].option;
320      }
321      flagConfigObj[configItem.title] = value;
322      if (configItem.addInfo) {
323        for (const [key, value] of Object.entries(configItem.addInfo)) {
324          flagConfigObj[key] = value;
325        }
326      }
327      return flagConfigObj;
328    } else {
329      return configItem;
330    }
331  }
332
333  static getFlagsConfigEnableStatus(flagName: string): boolean {
334    let config = FlagsConfig.getFlagsConfig(flagName);
335    let enable: boolean = false;
336    if (config && config[flagName]) {
337      enable = config[flagName] === 'Enabled';
338    }
339    return enable;
340  }
341
342  static updateFlagsConfig(key: string, value: unknown): void {
343    let flagsConfigStr = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY);
344    let flagConfigObj: Params = {};
345    if (flagsConfigStr !== null) {
346      flagConfigObj = JSON.parse(flagsConfigStr);
347    }
348    flagConfigObj[key] = value;
349    window.localStorage.setItem(FlagsConfig.FLAGS_CONFIG_KEY, JSON.stringify(flagConfigObj));
350  }
351}
352
353export interface FlagConfigItem {
354  title: string;
355  switchOptions: OptionItem[];
356  describeContent: string;
357  addInfo?: Params;
358}
359
360export interface OptionItem {
361  option: string;
362  selected?: boolean;
363}
364