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.isEnable) { 185 if (tintState.backgroundColor) { 186 this.changeBackground(tintState); 187 } 188 if (tintState.contentColor) { 189 this.changeContent(tintState); 190 } 191 } 192 } 193 194 setStatusBarEnable(isEnable: boolean): void { 195 Log.showInfo(TAG, `setStatusBarEnable, isEnable ${isEnable}`); 196 if (this.mStatusBarEnable == isEnable) { 197 return; 198 } 199 this.mStatusBarEnable = isEnable; 200 this.mStatusBarEnable ? WindowManager.showWindow(WindowType.STATUS_BAR).then(() => { 201 }).catch((err) => { 202 }) : WindowManager.hideWindow(WindowType.STATUS_BAR).then(() => { 203 }).catch((err) => { 204 }); 205 } 206 207 changeBackground(tintState: TintState): void{ 208 Log.showInfo(TAG, `changeBackground, backgroundColor: ${tintState.backgroundColor} region: ${JSON.stringify(tintState.region)}`); 209 let data = new StatusBarBackgroundData(); 210 data.backgroundColor = tintState.backgroundColor; 211 if (this.mStatusBarData.showHorizontal) { 212 if (!tintState.region) { 213 data.width = this.mStatusBarData.realWidth; 214 this.mBackgroundDatas[0] = data; 215 this.mBackgroundDatas[1] = new StatusBarBackgroundData(); 216 this.mBackgroundDatas[2] = new StatusBarBackgroundData(); 217 } else { 218 data.width = tintState.region.width; 219 if (tintState.region.left == this.mStatusBarData.left) { 220 this.mBackgroundDatas[0] = data; 221 } else if ((tintState.region.left + tintState.region.width) == (this.mStatusBarData.left + this.mStatusBarData.realWidth)) { 222 this.mBackgroundDatas[2] = data; 223 } else { 224 this.mBackgroundDatas[1] = data; 225 } 226 } 227 } else { 228 if (!tintState.region) { 229 data.width = this.mStatusBarData.realHeight; 230 this.mBackgroundDatas[0] = data; 231 this.mBackgroundDatas[1] = new StatusBarBackgroundData(); 232 this.mBackgroundDatas[2] = new StatusBarBackgroundData(); 233 } else { 234 data.width = tintState.region.height; 235 if (tintState.region.top == this.mStatusBarData.top) { 236 this.mBackgroundDatas[0] = data; 237 } else if ((tintState.region.top + tintState.region.height) == (this.mStatusBarData.top + this.mStatusBarData.realHeight)) { 238 this.mBackgroundDatas[2] = data; 239 } else { 240 this.mBackgroundDatas[1] = data; 241 } 242 } 243 } 244 Log.showInfo(TAG, `changeBackground, data: ${JSON.stringify(data)}`); 245 } 246 247 changeContent(tintState: TintState): void{ 248 Log.showInfo(TAG, `changeContent, contentColor: ${tintState.contentColor} region: ${JSON.stringify(tintState.region)}`); 249 let data = new StatusBarComponentGroupContentData(); 250 data.contentColor = tintState.contentColor; 251 if (this.mStatusBarData.showHorizontal) { 252 if (!tintState.region) { 253 data.width = this.mStatusBarData.realWidth; 254 this.mComponentGroupContentDatas[0] = data; 255 this.mComponentGroupContentDatas[1] = new StatusBarComponentGroupContentData(); 256 this.mComponentGroupContentDatas[2] = new StatusBarComponentGroupContentData(); 257 } else { 258 data.width = tintState.region.width; 259 if (tintState.region.left == this.mStatusBarData.left) { 260 this.mComponentGroupContentDatas[0] = data; 261 } else if ((tintState.region.left + tintState.region.width) == (this.mStatusBarData.left + this.mStatusBarData.realWidth)) { 262 this.mComponentGroupContentDatas[2] = data; 263 } else { 264 this.mComponentGroupContentDatas[1] = data; 265 } 266 } 267 } else { 268 if (!tintState.region) { 269 data.width = this.mStatusBarData.realHeight; 270 this.mComponentGroupContentDatas[0] = data; 271 this.mComponentGroupContentDatas[1] = new StatusBarComponentGroupContentData(); 272 this.mComponentGroupContentDatas[2] = new StatusBarComponentGroupContentData(); 273 } else { 274 data.width = tintState.region.height; 275 if (tintState.region.top == this.mStatusBarData.top) { 276 this.mComponentGroupContentDatas[0] = data; 277 } else if ((tintState.region.top + tintState.region.height) == (this.mStatusBarData.top + this.mStatusBarData.realHeight)) { 278 this.mComponentGroupContentDatas[2] = data; 279 } else { 280 this.mComponentGroupContentDatas[1] = data; 281 } 282 } 283 } 284 Log.showInfo(TAG, `changeContent, data: ${JSON.stringify(data)}`); 285 286 this.mComponentAreaMap.forEach((value: Rect, key: string) => { 287 this.changeComponentContent(key, value); 288 }); 289 } 290 291 changeComponentContent(id: string, area: Rect): void{ 292 Log.showInfo(TAG, `changeComponentContent, id ${id} area: ${JSON.stringify(area)}`); 293 if (this.mUseInWindowName != WindowType.STATUS_BAR) { 294 this.setComponentContent(id, '#FFFFFFFF'); 295 return; 296 } 297 let startPos = this.mStatusBarData.showHorizontal ? this.mStatusBarData.left : this.mStatusBarData.top; 298 for (let group of this.mComponentGroupContentDatas) { 299 if (group.width == 0) { 300 continue; 301 } 302 let endPos = group.width + startPos; 303 let componentStartPos: number; 304 let componentEndPos: number; 305 if (this.mStatusBarData.showHorizontal) { 306 componentStartPos = area.left; 307 componentEndPos = area.left + area.width; 308 } else { 309 componentStartPos = area.top; 310 componentEndPos = area.top + area.height; 311 } 312 if (!(componentEndPos < startPos || componentStartPos > endPos)) { 313 if (id === 'systemui_controlpanel' || id === 'systemui_notificationpanel') { 314 this.resetWindow(id, area); 315 } 316 this.setComponentContent(id, group.contentColor); 317 break; 318 } 319 startPos = endPos; 320 } 321 } 322 323 async resetWindow(id: string, area: Rect): Promise<void>{ 324 Log.showInfo(TAG, `resetWindow, id ${id} contentColor: ${JSON.stringify(area)}`); 325 let panelWidth; 326 let panelHeight; 327 let abilityName; 328 let windowName; 329 if (id === 'systemui_notificationpanel') { 330 abilityName = AbilityManager.ABILITY_NAME_NOTIFICATION_PANEL; 331 let initRect = AbilityManager.getAbilityData(abilityName, 'rect'); 332 Log.showInfo(TAG, `id ${id} initRect: ${JSON.stringify(initRect)}`); 333 panelWidth = initRect.width; 334 panelHeight = initRect.height; 335 windowName = WindowType.NOTIFICATION_PANEL; 336 } else if (id === 'systemui_controlpanel') { 337 abilityName = AbilityManager.ABILITY_NAME_CONTROL_PANEL; 338 let initRect = AbilityManager.getAbilityData(abilityName, 'rect'); 339 Log.showInfo(TAG, `id ${id} initRect: ${JSON.stringify(initRect)}`); 340 panelWidth = initRect.width; 341 panelHeight = initRect.height; 342 windowName = WindowType.CONTROL_PANEL; 343 } else { 344 return; 345 } 346 let rect = { 347 left: area.left + area.width - panelWidth, 348 top: area.height, 349 width: panelWidth, 350 height: panelHeight, 351 }; 352 AbilityManager.setAbilityData(abilityName, 'rect', rect); 353 await WindowManager.moveTo(windowName, rect); 354 } 355 356 setComponentContent(id: string, contentColor: string): void{ 357 Log.showInfo(TAG, `setComponentContent, id ${id} contentColor: ${contentColor}`); 358 getOrCreateTintContentInfo(id).contentColor = contentColor; 359 } 360 361 updateComponentArea(id: string, area: Area): void{ 362 Log.showInfo(TAG, `updateComponentArea, id ${id} area: ${JSON.stringify(area)}`); 363 let areaInfo = { 364 left: vp2px(area.globalPosition.x as number), 365 top: vp2px(area.globalPosition.y as number), 366 width: vp2px(area.width as number), 367 height: vp2px(area.height as number) 368 }; 369 this.mComponentAreaMap.set(id, areaInfo); 370 this.changeComponentContent(id, areaInfo); 371 } 372 373 setUseInWindowName(name: WindowType): void { 374 Log.showInfo(TAG, `setUseInWindowName, name ${name}`); 375 this.mUseInWindowName = name; 376 this.mComponentAreaMap.forEach((value: Rect, key: string) => { 377 this.changeComponentContent(key, value); 378 }); 379 } 380 381 getStatusBarData(): StatusBarData { 382 return this.mStatusBarData; 383 } 384 385 updateStatusBarData(data: StatusBarData): void{ 386 Log.showDebug(TAG, `updateStatusBarData, data: ${JSON.stringify(data)}`); 387 for (let key in data) { 388 this.mStatusBarData[key] = data[key]; 389 } 390 } 391 392 getEmptyTintContentInfo(): TintContentInfo{ 393 return this.mEmptyTintContentInfo; 394 } 395 396 getNotificationTintContentInfo(): TintContentInfo{ 397 return this.mNotificationTintContentInfo; 398 } 399 400 getPluginTintContentInfo(id: string): TintContentInfo{ 401 return getOrCreateTintContentInfo(id); 402 } 403 404 getBackgroundDatas(): StatusBarBackgroundData[]{ 405 return this.mBackgroundDatas; 406 } 407} 408 409let sStatusBarVM = createOrGet(StatusBarVM, TAG); 410 411export default sStatusBarVM;