1/* 2 * Copyright (c) 2021-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 Log from '../../../../../../../../common/src/main/ets/default/Log'; 17import EventManager from '../../../../../../../../common/src/main/ets/default/event/EventManager'; 18import { obtainLocalEvent } from '../../../../../../../../common/src/main/ets/default/event/EventUtil'; 19import AbilityManager from '../../../../../../../../common/src/main/ets/default/abilitymanager/abilityManager'; 20import createOrGet from '../../../../../../../../common/src/main/ets/default/SingleInstanceHelper'; 21import WindowManager, { WindowType } from '../../../../../../../../common/src/main/ets/default/WindowManager'; 22import TintStateManager, { TintState, TintContentInfo, getOrCreateTintContentInfo 23} from '../../../../../../../../common/src/main/ets/default/TintStateManager'; 24import { FASlotName, Rect } from '../../../../../../../../common/src/main/ets/default/Constants'; 25import { PluginType, PluginComponentData 26} from '../../../../../../../../common/src/main/ets/plugindatasource/common/Constants'; 27import StyleConfigurationCommon from '../../../../../../../../common/src/main/ets/default/StyleConfiguration'; 28import { StatusBarData, StatusBarBackgroundData, StatusBarComponentGroupContentData, StatusBarComponentData, 29 StatusBarConfig } from '../common/Constants'; 30import StatusBarService from '../model/StatusBarService'; 31import display from '@ohos.display'; 32export const STATUS_BAR_LAYOUT_KEY = 'StatusBarLayout'; 33 34export const STATUS_BAR_EMPTY_WIDTH_KEY = 'StatusBarEmptyWidth'; 35 36const TAG = 'StatusBarVM'; 37 38// @ts-ignore 39@Observed 40export class StringArray extends Array<string> {} 41 42export class StatusBarVM { 43 mIsStart = false; 44 mStatusBarLayout: string[][] = [[], [], []]; 45 mStatusBarEmptyWidth; 46 mUseCount = 0; 47 mStatusBarEnable = true; 48 mBackgroundDatas: StatusBarBackgroundData[]; 49 mStatusBarData: StatusBarData = { ...new StatusBarData() }; 50 mComponentAreaMap: Map<string, Rect> = new Map(); 51 mComponentGroupContentDatas: StatusBarComponentGroupContentData[] = [ 52 new StatusBarComponentGroupContentData(), new StatusBarComponentGroupContentData(), new StatusBarComponentGroupContentData()]; 53 mEmptyTintContentInfo: TintContentInfo = getOrCreateTintContentInfo(FASlotName.EMPTY); 54 mNotificationTintContentInfo: TintContentInfo = getOrCreateTintContentInfo(FASlotName.NOTIFICATION); 55 mUseInWindowName: WindowType = WindowType.STATUS_BAR; 56 57 constructor() { 58 Log.showInfo(TAG, 'constructor'); 59 this.mStatusBarData = AppStorage.SetAndLink(TAG + '_StatusBarData', this.mStatusBarData).get(); 60 StatusBarService.setStatusBarData(this.mStatusBarData); 61 62 this.mStatusBarLayout = AppStorage.SetAndLink(STATUS_BAR_LAYOUT_KEY, this.mStatusBarLayout).get(); 63 this.mStatusBarEmptyWidth = AppStorage.SetAndLink(STATUS_BAR_EMPTY_WIDTH_KEY, 0); 64 65 Log.showInfo(TAG, 'constructor mStatusBarLayout: ' + JSON.stringify(this.mStatusBarLayout)); 66 67 let defaultBackgroundDatas: StatusBarBackgroundData[] = []; 68 defaultBackgroundDatas.push(new StatusBarBackgroundData()); 69 defaultBackgroundDatas.push(new StatusBarBackgroundData()); 70 defaultBackgroundDatas.push(new StatusBarBackgroundData()); 71 if (this.mStatusBarData.showHorizontal) { 72 defaultBackgroundDatas[0].width = this.mStatusBarData.realWidth; 73 } else { 74 defaultBackgroundDatas[0].width = this.mStatusBarData.realHeight; 75 } 76 this.mBackgroundDatas = AppStorage.SetAndLink(TAG + '_BackgroundDatas', defaultBackgroundDatas).get(); 77 78 StatusBarService.registerListener(this); 79 } 80 81 install(): void { 82 Log.showInfo(TAG, `install, useCount: ${this.mUseCount}`); 83 if (!this.mUseCount) { 84 TintStateManager.getInstance().registerListener('status', this); 85 } 86 this.mUseCount++; 87 } 88 89 uninstall(): void { 90 Log.showInfo(TAG, `uninstall, useCount: ${this.mUseCount}`); 91 this.mUseCount--; 92 if (this.mUseCount) { 93 TintStateManager.getInstance().unregisterListener('status'); 94 } 95 } 96 97 initViewModel(config: StatusBarConfig, moduleName: string): void { 98 if (this.mIsStart) { 99 return; 100 } 101 Log.showInfo(TAG, `initViewModel, config: ${JSON.stringify(config)}`); 102 this.mIsStart = true; 103 104 this.install(); 105 StatusBarService.startService(config, moduleName); 106 } 107 108 setStatusBarLayout(layout: string[][]): void { 109 Log.showInfo(TAG, `setStatusBarLayout, layout: ${JSON.stringify(layout)}`); 110 for (let i = 0;i < layout.length; i++) { 111 if (JSON.stringify(layout[i]) != JSON.stringify(this.mStatusBarLayout[i])) { 112 this.mStatusBarLayout[i] = layout[i]; 113 } 114 } 115 Log.showInfo(TAG, `setStatusBarLayout, mStatusBarLayout: ${JSON.stringify(this.mStatusBarLayout)}`); 116 } 117 118 setStatusBarEmptyWidth(width: number): void{ 119 Log.showInfo(TAG, `setStatusBarEmptyWidth, width: ${width}`); 120 this.mStatusBarEmptyWidth.set(width); 121 } 122 123 setItemData(id: string, itemData: StatusBarComponentData): void{ 124 Log.showInfo(TAG, `setItemData, id: ${id} itemData: ${JSON.stringify(itemData)}`); 125 let storageKey: string = 'StatusBar_' + id; 126 if (itemData) { 127 AppStorage.SetOrCreate(storageKey, itemData); 128 } else { 129 let deleteRs: boolean = AppStorage.Delete(storageKey); 130 Log.showInfo(TAG, `setItemData, AppStorage.Delete rs: ${deleteRs} `); 131 } 132 this.setPluginData(id, itemData); 133 } 134 135 setPluginData(id: string, itemData: StatusBarComponentData): void{ 136 Log.showInfo(TAG, `setPluginData, itemData: ${JSON.stringify(itemData)}`); 137 if (itemData && itemData.pluginType == PluginType.PLUGIN_COMPONENT) { 138 let data = undefined; 139 if (itemData.actionData.pluginData && itemData.actionData.pluginData.data) { 140 data = JSON.parse(JSON.stringify(itemData.actionData.pluginData.data)); 141 if (Object.keys(data).length > 0) { 142 this.setPluginDataFontColorSize(id, data); 143 } 144 } 145 let pluginData = this.getPluginData(id); 146 pluginData.template = itemData.actionData.pluginData.template; 147 pluginData.data = data; 148 Log.showInfo(TAG, `setPluginData, pluginData: ${JSON.stringify(pluginData)} `); 149 } else { 150 let storageKey = 'StatusBar_PluginIcon_' + id; 151 if (AppStorage.Has(storageKey)) { 152 let deleteRs: boolean = AppStorage.Delete(storageKey); 153 Log.showInfo(TAG, `setPluginData, AppStorage.Delete rs: ${String(deleteRs)} `); 154 } 155 } 156 } 157 158 getPluginData(id: string): PluginComponentData { 159 Log.showInfo(TAG, `getPluginData, id: ${id}`); 160 let storageKey = 'StatusBar_PluginIcon_' + id; 161 if (!AppStorage.Has(storageKey)) { 162 AppStorage.SetOrCreate(storageKey, new PluginComponentData()); 163 } 164 return AppStorage.Get(storageKey); 165 } 166 167 setPluginDataFontColorSize(id: string, data): void { 168 if (!data['fontSize']) { 169 data['fontSize'] = StyleConfigurationCommon.getCommonStyle().statusBarFontSize; 170 } 171 if (!data['fontColor']) { 172 if (!this.mComponentAreaMap.get(id)) { 173 this.changeComponentContent(id, { left: 0, top: 0, width: 0, height: 0 }); 174 } 175 data['fontColor'] = this.getPluginTintContentInfo(id).contentColor; 176 } 177 } 178 179 onTintStateChange(tintState: TintState): void { 180 Log.showInfo(TAG, `onTintStateChange, tintState: ${JSON.stringify(tintState)}`); 181 if (typeof (tintState.isEnable) == 'boolean') { 182 this.setStatusBarEnable(tintState.isEnable); 183 } 184 if (tintState.backgroundColor) { 185 this.changeBackground(tintState); 186 } 187 if (tintState.contentColor) { 188 this.changeContent(tintState); 189 } 190 } 191 192 setStatusBarEnable(isEnable: boolean): void { 193 Log.showInfo(TAG, `setStatusBarEnable, isEnable ${isEnable}`); 194 if (this.mStatusBarEnable == isEnable) { 195 return; 196 } 197 this.mStatusBarEnable = isEnable; 198 this.mStatusBarEnable ? WindowManager.showWindow(WindowType.STATUS_BAR).then(() => { 199 }).catch((err) => { 200 }) : WindowManager.hideWindow(WindowType.STATUS_BAR).then(() => { 201 }).catch((err) => { 202 }); 203 } 204 205 changeBackground(tintState: TintState): void{ 206 Log.showInfo(TAG, `changeBackground, backgroundColor: ${tintState.backgroundColor} region: ${JSON.stringify(tintState.region)}`); 207 let data = new StatusBarBackgroundData(); 208 data.backgroundColor = tintState.backgroundColor; 209 if (this.mStatusBarData.showHorizontal) { 210 if (!tintState.region) { 211 data.width = this.mStatusBarData.realWidth; 212 this.mBackgroundDatas[0] = data; 213 this.mBackgroundDatas[1] = new StatusBarBackgroundData(); 214 this.mBackgroundDatas[2] = new StatusBarBackgroundData(); 215 } else { 216 data.width = tintState.region.width; 217 if (tintState.region.left == this.mStatusBarData.left) { 218 this.mBackgroundDatas[0] = data; 219 } else if ((tintState.region.left + tintState.region.width) == (this.mStatusBarData.left + this.mStatusBarData.realWidth)) { 220 this.mBackgroundDatas[2] = data; 221 } else { 222 this.mBackgroundDatas[1] = data; 223 } 224 } 225 } else { 226 if (!tintState.region) { 227 data.width = this.mStatusBarData.realHeight; 228 this.mBackgroundDatas[0] = data; 229 this.mBackgroundDatas[1] = new StatusBarBackgroundData(); 230 this.mBackgroundDatas[2] = new StatusBarBackgroundData(); 231 } else { 232 data.width = tintState.region.height; 233 if (tintState.region.top == this.mStatusBarData.top) { 234 this.mBackgroundDatas[0] = data; 235 } else if ((tintState.region.top + tintState.region.height) == (this.mStatusBarData.top + this.mStatusBarData.realHeight)) { 236 this.mBackgroundDatas[2] = data; 237 } else { 238 this.mBackgroundDatas[1] = data; 239 } 240 } 241 } 242 Log.showInfo(TAG, `changeBackground, data: ${JSON.stringify(data)}`); 243 } 244 245 changeContent(tintState: TintState): void{ 246 Log.showInfo(TAG, `changeContent, contentColor: ${tintState.contentColor} region: ${JSON.stringify(tintState.region)}`); 247 let data = new StatusBarComponentGroupContentData(); 248 data.contentColor = tintState.contentColor; 249 if (this.mStatusBarData.showHorizontal) { 250 if (!tintState.region) { 251 data.width = this.mStatusBarData.realWidth; 252 this.mComponentGroupContentDatas[0] = data; 253 this.mComponentGroupContentDatas[1] = new StatusBarComponentGroupContentData(); 254 this.mComponentGroupContentDatas[2] = new StatusBarComponentGroupContentData(); 255 } else { 256 data.width = tintState.region.width; 257 if (tintState.region.left == this.mStatusBarData.left) { 258 this.mComponentGroupContentDatas[0] = data; 259 } else if ((tintState.region.left + tintState.region.width) == (this.mStatusBarData.left + this.mStatusBarData.realWidth)) { 260 this.mComponentGroupContentDatas[2] = data; 261 } else { 262 this.mComponentGroupContentDatas[1] = data; 263 } 264 } 265 } else { 266 if (!tintState.region) { 267 data.width = this.mStatusBarData.realHeight; 268 this.mComponentGroupContentDatas[0] = data; 269 this.mComponentGroupContentDatas[1] = new StatusBarComponentGroupContentData(); 270 this.mComponentGroupContentDatas[2] = new StatusBarComponentGroupContentData(); 271 } else { 272 data.width = tintState.region.height; 273 if (tintState.region.top == this.mStatusBarData.top) { 274 this.mComponentGroupContentDatas[0] = data; 275 } else if ((tintState.region.top + tintState.region.height) == (this.mStatusBarData.top + this.mStatusBarData.realHeight)) { 276 this.mComponentGroupContentDatas[2] = data; 277 } else { 278 this.mComponentGroupContentDatas[1] = data; 279 } 280 } 281 } 282 Log.showInfo(TAG, `changeContent, data: ${JSON.stringify(data)}`); 283 284 this.mComponentAreaMap.forEach((value: Rect, key: string) => { 285 this.changeComponentContent(key, value); 286 }); 287 } 288 289 changeComponentContent(id: string, area: Rect): void{ 290 Log.showInfo(TAG, `changeComponentContent, id ${id} area: ${JSON.stringify(area)}`); 291 if (this.mUseInWindowName != WindowType.STATUS_BAR) { 292 this.setComponentContent(id, '#FFFFFFFF'); 293 return; 294 } 295 let startPos = this.mStatusBarData.showHorizontal ? this.mStatusBarData.left : this.mStatusBarData.top; 296 for (let group of this.mComponentGroupContentDatas) { 297 if (group.width == 0) { 298 continue; 299 } 300 let endPos = group.width + startPos; 301 let componentStartPos: number; 302 let componentEndPos: number; 303 if (this.mStatusBarData.showHorizontal) { 304 componentStartPos = area.left; 305 componentEndPos = area.left + area.width; 306 } else { 307 componentStartPos = area.top; 308 componentEndPos = area.top + area.height; 309 } 310 if (!(componentEndPos < startPos || componentStartPos > endPos)) { 311 if (id === 'systemui_controlpanel' || id === 'systemui_notificationpanel') { 312 this.resetWindow(id, area); 313 } 314 this.setComponentContent(id, group.contentColor); 315 break; 316 } 317 startPos = endPos; 318 } 319 } 320 321 async resetWindow(id: string, area: Rect): Promise<void>{ 322 Log.showInfo(TAG, `resetWindow, id ${id} contentColor: ${JSON.stringify(area)}`); 323 let panelWidth; 324 let panelHeight; 325 let abilityName; 326 let windowName; 327 if (id === 'systemui_notificationpanel') { 328 abilityName = AbilityManager.ABILITY_NAME_NOTIFICATION_PANEL; 329 let initRect = AbilityManager.getAbilityData(abilityName, 'rect'); 330 Log.showInfo(TAG, `id ${id} initRect: ${JSON.stringify(initRect)}`); 331 panelWidth = initRect.width; 332 panelHeight = initRect.height; 333 windowName = WindowType.NOTIFICATION_PANEL; 334 } else if (id === 'systemui_controlpanel') { 335 abilityName = AbilityManager.ABILITY_NAME_CONTROL_PANEL; 336 let initRect = AbilityManager.getAbilityData(abilityName, 'rect'); 337 Log.showInfo(TAG, `id ${id} initRect: ${JSON.stringify(initRect)}`); 338 panelWidth = initRect.width; 339 panelHeight = initRect.height; 340 windowName = WindowType.CONTROL_PANEL; 341 } else { 342 return; 343 } 344 let rect = { 345 left: area.left + area.width - panelWidth, 346 top: area.height, 347 width: panelWidth, 348 height: panelHeight, 349 }; 350 AbilityManager.setAbilityData(abilityName, 'rect', rect); 351 await WindowManager.moveTo(windowName, rect); 352 } 353 354 setComponentContent(id: string, contentColor: string): void{ 355 Log.showInfo(TAG, `setComponentContent, id ${id} contentColor: ${contentColor}`); 356 getOrCreateTintContentInfo(id).contentColor = contentColor; 357 } 358 359 updateComponentArea(id: string, area: Area): void{ 360 Log.showInfo(TAG, `updateComponentArea, id ${id} area: ${JSON.stringify(area)}`); 361 let areaInfo = { 362 left: vp2px(area.globalPosition.x as number), 363 top: vp2px(area.globalPosition.y as number), 364 width: vp2px(area.width as number), 365 height: vp2px(area.height as number) 366 }; 367 this.mComponentAreaMap.set(id, areaInfo); 368 this.changeComponentContent(id, areaInfo); 369 } 370 371 setUseInWindowName(name: WindowType): void { 372 Log.showInfo(TAG, `setUseInWindowName, name ${name}`); 373 this.mUseInWindowName = name; 374 this.mComponentAreaMap.forEach((value: Rect, key: string) => { 375 this.changeComponentContent(key, value); 376 }); 377 } 378 379 getStatusBarData(): StatusBarData { 380 return this.mStatusBarData; 381 } 382 383 updateStatusBarData(data: StatusBarData): void{ 384 Log.showDebug(TAG, `updateStatusBarData, data: ${JSON.stringify(data)}`); 385 for (let key in data) { 386 this.mStatusBarData[key] = data[key]; 387 } 388 } 389 390 getEmptyTintContentInfo(): TintContentInfo{ 391 return this.mEmptyTintContentInfo; 392 } 393 394 getNotificationTintContentInfo(): TintContentInfo{ 395 return this.mNotificationTintContentInfo; 396 } 397 398 getPluginTintContentInfo(id: string): TintContentInfo{ 399 return getOrCreateTintContentInfo(id); 400 } 401 402 getBackgroundDatas(): StatusBarBackgroundData[]{ 403 return this.mBackgroundDatas; 404 } 405} 406 407let sStatusBarVM = createOrGet(StatusBarVM, TAG); 408 409export default sStatusBarVM;