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