• 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 */
15import { BaseElement, element } from '../../../../../base-ui/BaseElement';
16import { LitSelect } from '../../../../../base-ui/select/LitSelect';
17import { SelectionParam } from '../../../../bean/BoxSelection';
18import { queryXpowerComponentTop } from '../../../../database/sql/Xpower.sql';
19import { SpSystemTrace } from '../../../SpSystemTrace';
20import { LitTabs } from '../../../../../base-ui/tabs/lit-tabs';
21import { LitTabpane } from '../../../../../base-ui/tabs/lit-tabpane';
22import { TabPaneXpowerComponentAudio } from './TabPaneXpowerComponentAudio';
23import { TabPaneXpowerComponentCamera } from './TabPaneXpowerComponentCamera';
24import { TabPaneXpowerComponentCpu } from './TabPaneXpowerComponentCpu';
25import { TabPaneXpowerComponentDisplay } from './TabPaneXpowerComponentDisplay';
26import { LitTable } from '../../../../../base-ui/table/lit-table';
27
28@element('tabpane-xpower-component-top')
29export class TabPaneXpowerComponentTop extends BaseElement {
30  private currentSelection: Array<XpowerComponentTopStruct> = [];
31  private currentXpowerComponentTopValue: SelectionParam | undefined;
32  private xpowerComponentTopTbl: HTMLDivElement | null | undefined;
33  private xpowerComponentTopRange: HTMLLabelElement | null | undefined;
34  private xpowerComponentTopSelect: LitSelect | null | undefined;
35  private options: Set<string> = new Set();
36  private componentTypeList: Array<string> = [];
37  private currentTabKey: string | undefined;
38  private currentTabPane?: BaseElement;
39  private tabMap: Map<string, BaseElement> = new Map<string, BaseElement>();
40
41  set data(xpowerComponentTopValue: SelectionParam) {
42    //@ts-ignore
43    this.xpowerComponentTopTbl?.shadowRoot?.querySelector('.table')?.style?.height = `${
44      this.parentElement!.clientHeight - 45
45    }px`;
46    this.xpowerComponentTopRange!.textContent = `Selected range: ${parseFloat(
47      ((xpowerComponentTopValue.rightNs - xpowerComponentTopValue.leftNs) / 1000000.0).toFixed(5)
48    )} ms`;
49    if (xpowerComponentTopValue === this.currentXpowerComponentTopValue) {
50      return;
51    }
52    this.componentTypeList = [
53      'audio',
54      'bluetooth',
55      'flashlight',
56      'location',
57      'wifiscan',
58      'camera',
59      'cpu',
60      'display',
61      'gpu',
62    ];
63    this.currentXpowerComponentTopValue = xpowerComponentTopValue;
64    this.getComponentTopData(xpowerComponentTopValue);
65  }
66
67  async getComponentTopData(xpowerComponentTopValue: SelectionParam): Promise<void> {
68    let componentTopList = await queryXpowerComponentTop(
69      xpowerComponentTopValue.leftNs,
70      xpowerComponentTopValue.rightNs,
71      3000000000
72    );
73    this.createSelectComponentTopData(componentTopList || []).then(() => {
74      this.currentTabKey = this.xpowerComponentTopSelect!.value;
75      this.showTabPane();
76    });
77  }
78
79  async createSelectComponentTopData(list: Array<XpowerComponentTopStruct>): Promise<XpowerComponentTopStruct[]> {
80    this.options = new Set();
81    let componentTopStructList: XpowerComponentTopStruct[] = [];
82    if (list.length > 0) {
83      for (let i = 0; i < list.length; i++) {
84        const selectComponentTopData = {
85          startNS: list[i].startNS,
86          startMS: list[i].startNS / 1_000_000,
87          componentTypeId: list[i].componentTypeId,
88          appName: list[i].appName,
89          componentTypeName: SpSystemTrace.DATA_DICT.get(list[i].componentTypeId) || '',
90          appNameStr: SpSystemTrace.DATA_DICT.get(list[i].appName) || '',
91          backgroundDuration: list[i].backgroundDuration,
92          backgroundEnergy: list[i].backgroundEnergy,
93          foregroundDuration: list[i].foregroundDuration,
94          foregroundEnergy: list[i].foregroundEnergy,
95          screenOffDuration: list[i].screenOffDuration,
96          screenOffEnergy: list[i].screenOffEnergy,
97          screenOnDuration: list[i].screenOnDuration,
98          screenOnEnergy: list[i].screenOnEnergy,
99          cameraId: list[i].cameraId,
100          uId: list[i].uId,
101          load: list[i].load,
102          appUsageDuration: list[i].appUsageDuration,
103          appUsageEnergy: list[i].appUsageEnergy,
104        };
105        this.options.add(selectComponentTopData.componentTypeName);
106        componentTopStructList.push(selectComponentTopData);
107      }
108    }
109    this.initOptions();
110    this.currentSelection = componentTopStructList;
111    return componentTopStructList;
112  }
113
114  initElements(): void {
115    this.xpowerComponentTopTbl = this.shadowRoot?.querySelector<HTMLDivElement>('#tb-counter');
116    this.xpowerComponentTopSelect = this.shadowRoot?.querySelector<LitSelect>('#tab-select');
117    this.xpowerComponentTopRange = this.shadowRoot?.querySelector('#time-range');
118  }
119
120  private setColumns(table: LitTable): void {
121    if (!table!.columns) {
122      table!.gridTemplateColumns = [];
123      table!.columns = table!.slotArr;
124      table!.columns.forEach((a: unknown, i: unknown) => {
125        // @ts-ignore
126        if (a.tagName === 'LIT-TABLE-COLUMN') {
127          // @ts-ignore
128          table!.gridTemplateColumns.push(a.getAttribute('width') || '1fr');
129        }
130      });
131    }
132  }
133
134  private initSortIcon(thead: HTMLDivElement, table: LitTable): void {
135    const thTable = thead!.querySelector('.th');
136    if (thead && thead!.hasAttribute('sort')) {
137      const list = thTable!.querySelectorAll('div');
138      thead!.removeAttribute('sort');
139      list.forEach((item) => {
140        item.querySelectorAll('svg').forEach((svg) => {
141          svg.style.display = 'none';
142        });
143      });
144    }
145  }
146
147  private showTabPane(): void {
148    if (
149      this.currentTabPane &&
150      this.xpowerComponentTopTbl!.children.length > 0 &&
151      this.xpowerComponentTopTbl?.children[0] === this.currentTabPane
152    ) {
153      this.xpowerComponentTopTbl?.removeChild(this.currentTabPane);
154    }
155    if (this.currentTabKey && this.currentSelection) {
156      if (this.tabMap.has(this.currentTabKey)) {
157        this.currentTabPane = this.tabMap.get(this.currentTabKey);
158      } else {
159        let tab = this.createTabBySelector();
160        if (tab) {
161          this.currentTabPane = tab;
162          this.tabMap.set(this.currentTabKey, tab);
163        }
164      }
165      if (this.currentTabPane) {
166        this.xpowerComponentTopTbl?.appendChild(this.currentTabPane);
167        let table = this.currentTabPane.shadowRoot?.querySelector<LitTable>('lit-table')!;
168        let theadEl = table!.shadowRoot?.querySelector<HTMLDivElement>('.thead')!;
169        this.initSortIcon(theadEl, table);
170        this.setColumns(table);
171        // @ts-ignore
172        this.currentTabPane.data = this.currentSelection.filter(
173          (item) => item.componentTypeName === this.currentTabKey
174        );
175      }
176      let tabs = document
177        .querySelector('body > sp-application')
178        ?.shadowRoot?.querySelector('#sp-system-trace')
179        ?.shadowRoot?.querySelector('div > trace-sheet')
180        ?.shadowRoot?.querySelector('#tabs') as LitTabs;
181      let pane = document
182        .querySelector('body > sp-application')
183        ?.shadowRoot?.querySelector('#sp-system-trace')
184        ?.shadowRoot?.querySelector('div > trace-sheet')
185        ?.shadowRoot?.querySelector('#box-xpower-component-top') as LitTabpane;
186      tabs.activeByKey(pane.key);
187    }
188  }
189
190  private initOptions(): void {
191    let optionsArr = Array.from(this.options);
192    this.xpowerComponentTopSelect!.dataSource = optionsArr;
193    // 默认选中第一个
194    this.xpowerComponentTopSelect?.querySelector('lit-select-option')?.setAttribute('selected', '');
195    this.currentTabKey = optionsArr[0];
196    this.xpowerComponentTopSelect!.defaultValue = this.currentTabKey || '';
197    this.xpowerComponentTopSelect!.value = this.currentTabKey || '';
198    this.xpowerComponentTopSelect!.querySelectorAll('lit-select-option').forEach((option) => {
199      option.addEventListener('onSelected', () => {
200        this.xpowerComponentTopSelect?.shadowRoot!.querySelectorAll('lit-select-option').forEach((o) => {
201          o.removeAttribute('selected');
202        });
203        option.setAttribute('selected', '');
204        this.currentTabKey = option.getAttribute('value') || '';
205        this.xpowerComponentTopSelect!.value = option.getAttribute('value') || '';
206        this.showTabPane();
207      });
208    });
209  }
210
211  private createTabBySelector(): BaseElement {
212    if (this.componentTypeList.slice(0, 5).includes(this.currentTabKey!)) {
213      // 'audio','bluetooth', 'flashlight', 'location','wifiscan'
214      return new TabPaneXpowerComponentAudio();
215    } else if (this.componentTypeList.slice(5, 6).includes(this.currentTabKey!)) {
216      // 'camera'
217      return new TabPaneXpowerComponentCamera();
218    } else if (this.componentTypeList.slice(6, 7).includes(this.currentTabKey!)) {
219      // 'cpu'
220      return new TabPaneXpowerComponentCpu();
221    } else {
222      // 'display', 'gpu'
223      return new TabPaneXpowerComponentDisplay();
224    }
225  }
226
227  connectedCallback(): void {
228    super.connectedCallback();
229    new ResizeObserver((entries) => {
230      // 32 select的高度
231      if (this.parentElement!.clientHeight < 32) {
232        this.shadowRoot!.querySelector<HTMLDivElement>('.bottom_select')!.style.display = 'none';
233      } else {
234        this.shadowRoot!.querySelector<HTMLDivElement>('.bottom_select')!.style.display = 'block';
235      }
236    }).observe(this.parentElement!);
237  }
238
239  initHtml(): string {
240    return `
241        <style>
242        .xpower-counter-label{
243            margin-bottom: 5px;
244        }
245        :host{
246            padding: 10px 10px;
247            display: flex;
248            flex-direction: column;
249            height: calc(100% - 32px);
250        }
251        #tb-counter{
252            height: 100%;
253        }
254        .bottom_select{
255            height: 30px;
256            background: var(--dark-background4,#F2F2F2);
257            border-top: 1px solid var(--dark-border1,#c9d0da);
258            display: flex;
259            align-items: center;
260            border: solid rgb(216,216,216) 1px;
261            float: left;
262            position: fixed;
263            bottom: 0;
264            width: 100%;
265            z-index: 2;
266        }
267        #tab-select{
268            margin-left: 10px;
269            z-index: 2;
270        }
271        </style>
272        <label id="time-range" class="xpower-counter-label" style="position: sticky; top: 0; width: 100%;height: 20px;text-align: end;font-size: 10pt;">Selected range:0.0 ms</label>
273        <div id="tb-counter"></div>
274        <div class="bottom_select">
275            <lit-select id="tab-select" placeholder="please choose" tabselect></lit-select>
276        </div>
277        `;
278  }
279}
280
281export class XpowerComponentTopStruct {
282  startNS: number = 0;
283  startMS: number = 0;
284  componentTypeId: number = 0;
285  componentTypeName: string = '';
286  appNameStr: string = '';
287  appName: number = 0;
288  backgroundDuration: number = 0;
289  backgroundEnergy: number = 0;
290  foregroundDuration: number = 0;
291  foregroundEnergy: number = 0;
292  screenOffDuration: number = 0;
293  screenOffEnergy: number = 0;
294  screenOnDuration: number = 0;
295  screenOnEnergy: number = 0;
296  cameraId: number = 0;
297  uId: number = 0;
298  load: number = 0;
299  appUsageDuration: number = 0;
300  appUsageEnergy: number = 0;
301}
302