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 { FASlotName } from '../../../../../../../../common/src/main/ets/default/Constants'; 18import createOrGet from '../../../../../../../../common/src/main/ets/default/SingleInstanceHelper'; 19import SwitchUserManager, { UserInfo } from '../../../../../../../../common/src/main/ets/default/SwitchUserManager'; 20import { ItemComponentData, PluginComponentData, FilterData 21} from '../../../../../../../../common/src/main/ets/plugindatasource/common/Constants'; 22import PluginDataSourceAdapter from '../../../../../../../../common/src/main/ets/plugindatasource/PluginDataSourceAdapter'; 23import AbilityManager from '../../../../../../../../common/src/main/ets/default/abilitymanager/abilityManager'; 24import Constants, { StatusBarData, StatusBarComponentData, LayoutGroup, StatusBarConfig } from '../common/Constants'; 25import { parseEventString } from '../../../../../../../../common/src/main/ets/default/event/EventUtil'; 26 27export interface StatusBarListener { 28 setStatusBarLayout(layout: string[][]): void; 29 30 setStatusBarEmptyWidth(width: number): void; 31 32 setItemData(id: string, itemData: StatusBarComponentData): void; 33} 34 35const TAG = 'StatusBarModel'; 36const STATUSBAR_SOURCE_CONFIG = { 37 action: 'com.ohos.systemui.action.BAR_ICON', 38 filterDatas: new Array<FilterData>(), 39 loaderConfig: { 40 MetaSource: { 41 action: 'com.ohos.systemui.action.BAR_ICON', 42 permission: null, 43 }, 44 PluginSourceLoader: { 45 action: 'com.ohos.systemui.action.BAR_ICON', 46 permission: null, 47 }, 48 }, 49}; 50 51function parseItemData(itemData: ItemComponentData): StatusBarComponentData { 52 let { isShowLabel, isShowIcon, selectedClickAction, relationWindowId, ...other } = itemData.actionData?.extra; 53 let selectAction = parseEventString(selectedClickAction); 54 let statusBarItemData: StatusBarComponentData = { 55 ...itemData, 56 isShowLabel: isShowLabel ? isShowLabel !== false : false, 57 isShowIcon: isShowIcon ? isShowIcon !== false : true, 58 canSelect: selectAction ? true : false, 59 relationWindowId: relationWindowId, 60 actionData: { 61 ...itemData.actionData, 62 selectedClickAction: selectAction, 63 extra: undefined, 64 }, 65 }; 66 return statusBarItemData; 67} 68 69export class StatusBarService { 70 mIsStart = false; 71 mAdapter: PluginDataSourceAdapter; 72 mListener: StatusBarListener | undefined; 73 mConfig: StatusBarConfig; 74 mStatusBarData: StatusBarData; 75 mStatusBarLayoutGroupTemplate: string[][] = []; 76 mStatusBarAllLayout: string[]; 77 78 constructor() { 79 Log.showInfo(TAG, 'constructor'); 80 } 81 82 setStatusBarData(data: StatusBarData): void{ 83 Log.showInfo(TAG, 'setStatusBarData'); 84 this.mStatusBarData = data; 85 } 86 87 startService(config: StatusBarConfig, moduleName: string): void { 88 if (this.mIsStart) { 89 return; 90 } 91 Log.showInfo(TAG, 'start StatusBarService.'); 92 this.mIsStart = true; 93 94 this.parseConfig(config); 95 96 SwitchUserManager.getInstance().registerListener(this); 97 STATUSBAR_SOURCE_CONFIG.filterDatas = config.MetaSlots; 98 this.mAdapter = new PluginDataSourceAdapter(TAG, AbilityManager.getContext(AbilityManager.ABILITY_NAME_STATUS_BAR), this, moduleName); 99 this.mAdapter.setWant(globalThis[Constants.PLUGIN_COMPONENT_OWNER_WANT_KEY]); 100 this.mAdapter.initDataSource(STATUSBAR_SOURCE_CONFIG); 101 } 102 103 stopService(): void { 104 if (!this.mIsStart) { 105 return; 106 } 107 Log.showInfo(TAG, 'stop StatusBarService.'); 108 this.mIsStart = false; 109 110 this.mAdapter.clearAll(); 111 } 112 113 parseConfig(config: StatusBarConfig): void { 114 Log.showInfo(TAG, `parseConfig, config: ${JSON.stringify(config)}`); 115 this.mConfig = config; 116 117 const groupIds = [Constants.GROUP_ID_LEFT, Constants.GROUP_ID_CENTER, Constants.GROUP_ID_RIGHT]; 118 groupIds.forEach((groupId) => { 119 for (const groupInfo of config.LayoutGroups) { 120 if (groupId == groupInfo.id) { 121 this.mStatusBarLayoutGroupTemplate.push([...groupInfo.Components]); 122 break; 123 } 124 } 125 }); 126 Log.showInfo(TAG, `parseConfig, statusBarLayoutGroupTemplate: ${JSON.stringify(this.mStatusBarLayoutGroupTemplate)}`); 127 128 this.mStatusBarAllLayout = [...config.LocalSlots]; 129 this.onDisplayRotate(0); 130 } 131 132 calcStatusBarLayout(): void { 133 Log.showInfo(TAG, 'calcStatusBarLayout'); 134 let statusBarLayout: string[][] = []; 135 this.mStatusBarLayoutGroupTemplate.forEach(componentsTemplate => { 136 let components: string [] = []; 137 for (let componentTemplate of componentsTemplate) { 138 if (this.mStatusBarAllLayout.indexOf(componentTemplate) >= 0) { 139 components.push(componentTemplate); 140 } 141 } 142 statusBarLayout.push(components); 143 }); 144 Log.showDebug(TAG, `calcStatusBarLayout, statusBarLayout: ${JSON.stringify(statusBarLayout)}`); 145 this.mListener?.setStatusBarLayout(statusBarLayout); 146 } 147 148 userChange(userInfo: UserInfo): void { 149 Log.showInfo(TAG, 'userChange'); 150 this.mAdapter.loadData(userInfo.userId); 151 } 152 153 initFinish(): void { 154 Log.showInfo(TAG, 'initFinish'); 155 SwitchUserManager.getInstance() 156 .getCurrentUserInfo() 157 .then((userInfo) => { 158 this.mAdapter.loadData(userInfo.userId); 159 }).catch((err) => { 160 }); 161 } 162 163 registerListener(listener: StatusBarListener | undefined): void { 164 Log.showInfo(TAG, `registerListener, listener: ${listener}`); 165 this.mListener = listener; 166 } 167 168 onItemAdd(itemData: ItemComponentData): void { 169 Log.showInfo(TAG, 'onItemAdd'); 170 let statusBarData: StatusBarComponentData = parseItemData(itemData); 171 let id = itemData.id; 172 this.mListener?.setItemData(id, statusBarData); 173 if (this.mStatusBarAllLayout.indexOf(id) < 0) { 174 this.mStatusBarAllLayout.push(id); 175 Log.showInfo(TAG, `onItemAdd, mStatusBarAllLayout: ${JSON.stringify(this.mStatusBarAllLayout)}`); 176 this.calcStatusBarLayout(); 177 } 178 } 179 180 onItemRemove(itemData: ItemComponentData): void { 181 Log.showInfo(TAG, 'onItemRemove'); 182 let id = itemData.id; 183 if (this.mStatusBarAllLayout.indexOf(id) >= 0) { 184 this.mStatusBarAllLayout.splice(this.mStatusBarAllLayout.indexOf(id), 1); 185 Log.showInfo(TAG, `onItemRemove, mStatusBarAllLayout: ${JSON.stringify(this.mStatusBarAllLayout)}`); 186 this.calcStatusBarLayout(); 187 } 188 this.mListener?.setItemData(id, undefined); 189 } 190 191 onDisplayRotate(rotation: number): void { 192 Log.showInfo(TAG, `onDisplayRotate, rotation: ${rotation}`); 193 let position: string = this.calcEmptyAreaPosition(rotation); 194 this.onEmptyAreaChange(position, rotation); 195 } 196 197 calcEmptyAreaPosition(rotation: number): string { 198 Log.showInfo(TAG, `calcEmptyAreaPosition, rotation: ${rotation}`); 199 let configEmptyPosition = this.mConfig.emptyPosition; 200 if (!configEmptyPosition || configEmptyPosition.x1 == configEmptyPosition.x2 || configEmptyPosition.y1 == configEmptyPosition.y2) { 201 return null; 202 } 203 204 let leftRightArea = this.calcStatusBarLeftRightArea(); 205 let statusBarLeft = leftRightArea.left; 206 let statusBarRight = leftRightArea.right; 207 208 let emptyPosition; 209 if (rotation == 0) { 210 emptyPosition = { ...configEmptyPosition }; 211 } else if (rotation == 90) { 212 emptyPosition = { 213 x1: this.mStatusBarData.displayWidth - configEmptyPosition.y2, 214 y1: configEmptyPosition.x1, 215 x2: this.mStatusBarData.displayWidth - configEmptyPosition.y1, 216 y2: configEmptyPosition.x2 217 }; 218 } else if (rotation == 180) { 219 emptyPosition = { 220 x1: this.mStatusBarData.displayWidth - configEmptyPosition.x2, 221 y1: this.mStatusBarData.displayHeight - configEmptyPosition.y2, 222 x2: this.mStatusBarData.displayWidth - configEmptyPosition.x1, 223 y2: this.mStatusBarData.displayHeight - configEmptyPosition.y1, 224 }; 225 } else { 226 emptyPosition = { 227 x1: configEmptyPosition.y1, 228 y1: this.mStatusBarData.displayHeight - configEmptyPosition.x2, 229 x2: configEmptyPosition.y2, 230 y2: this.mStatusBarData.displayHeight - configEmptyPosition.x1 231 }; 232 } 233 234 let isGlandLeft = this.isEmptyAreaGlandStatusBar(emptyPosition, statusBarLeft); 235 let isGlandRight = this.isEmptyAreaGlandStatusBar(emptyPosition, statusBarRight); 236 Log.showInfo(TAG, `calcEmptyAreaPosition, gland: ${isGlandLeft} ${isGlandRight}`); 237 if (isGlandLeft && isGlandRight) { 238 return Constants.EMPTY_AREA_POSITION_CENTER; 239 } else if (isGlandLeft) { 240 return Constants.EMPTY_AREA_POSITION_LEFT; 241 } else if (isGlandRight) { 242 return Constants.EMPTY_AREA_POSITION_RIGHT; 243 } else { 244 return null; 245 } 246 } 247 248 calcStatusBarLeftRightArea(): { 249 left: { 250 x1: number; 251 y1: number; 252 x2: number; 253 y2: number; 254 }, 255 right: { 256 x1: number; 257 y1: number; 258 x2: number; 259 y2: number; 260 } 261 }{ 262 let statusBarLeft; 263 let statusBarRight; 264 if (this.mStatusBarData.showHorizontal) { 265 statusBarLeft = { 266 x1: this.mStatusBarData.left, 267 y1: this.mStatusBarData.top, 268 x2: this.mStatusBarData.left + this.mStatusBarData.realWidth / 2, 269 y2: this.mStatusBarData.top + this.mStatusBarData.realHeight 270 }; 271 statusBarRight = { 272 x1: statusBarLeft.x2, 273 y1: statusBarLeft.y1, 274 x2: this.mStatusBarData.left + this.mStatusBarData.realWidth, 275 y2: statusBarLeft.y2 276 }; 277 } else { 278 statusBarLeft = { 279 x1: this.mStatusBarData.left, 280 y1: this.mStatusBarData.top, 281 x2: this.mStatusBarData.left + this.mStatusBarData.realWidth, 282 y2: this.mStatusBarData.top + this.mStatusBarData.realHeight / 2 283 }; 284 statusBarRight = { 285 x1: statusBarLeft.x1, 286 y1: statusBarLeft.y2, 287 x2: statusBarLeft.x2, 288 y2: this.mStatusBarData.top + this.mStatusBarData.realHeight 289 }; 290 } 291 Log.showInfo(TAG, `calcEmptyAreaPosition, statusBarLeft: ${JSON.stringify(statusBarLeft)} statusBarRight: ${JSON.stringify(statusBarRight)}`); 292 return { left: statusBarLeft, right: statusBarRight }; 293 } 294 295 isEmptyAreaGlandStatusBar(emptyPosition: { 296 x1: number; 297 y1: number; 298 x2: number; 299 y2: number; 300 }, statusBarArea: { 301 x1: number; 302 y1: number; 303 x2: number; 304 y2: number; 305 }): boolean { 306 Log.showInfo(TAG, `isEmptyAreaGlandStatusBar, emptyPosition: ${JSON.stringify(emptyPosition)} statusBarArea: ${JSON.stringify(statusBarArea)}`); 307 let ex1 = emptyPosition.x1; 308 let ey1 = emptyPosition.y1; 309 let ex2 = emptyPosition.x2; 310 let ey2 = emptyPosition.y2; 311 let x1 = statusBarArea.x1; 312 let y1 = statusBarArea.y1; 313 let x2 = statusBarArea.x2; 314 let y2 = statusBarArea.y2; 315 316 if (ex1 >= x1 && ex1 <= x2 && ey1 >= y1 && ey1 <= y2) { 317 return true; 318 } else if (ex2 >= x1 && ex2 <= x2 && ey1 >= y1 && ey1 <= y2) { 319 return true; 320 } else if (ex1 >= x1 && ex1 <= x2 && ey2 >= y1 && ey2 <= y2) { 321 return true; 322 } else if (ex2 >= x1 && ex2 <= x2 && ey2 >= y1 && ey2 <= y2) { 323 return true; 324 } 325 return false; 326 } 327 328 onEmptyAreaChange(position: string, rotation: number): void { 329 Log.showInfo(TAG, `onEmptyAreaChange, position: ${position} rotation: ${rotation}`); 330 this.calcEmptyWidth(rotation); 331 this.setEmptyAreaToLayoutTemplate(position); 332 let id = FASlotName.EMPTY; 333 if (this.mStatusBarAllLayout.indexOf(id) >= 0) { 334 this.mStatusBarAllLayout.splice(this.mStatusBarAllLayout.indexOf(id), 1); 335 } 336 if (position) { 337 this.mStatusBarAllLayout.push(id); 338 } 339 Log.showInfo(TAG, `onEmptyAreaChange, mStatusBarAllLayout: ${JSON.stringify(this.mStatusBarAllLayout)}`); 340 this.calcStatusBarLayout(); 341 } 342 343 setEmptyAreaToLayoutTemplate(position: string): void { 344 Log.showInfo(TAG, `setEmptyAreaToLayoutTemplate, position: ${position}`); 345 for (let componentsTemplate of this.mStatusBarLayoutGroupTemplate) { 346 let index = componentsTemplate.indexOf(FASlotName.EMPTY); 347 if (index >= 0) { 348 componentsTemplate.splice(index, 1); 349 break; 350 } 351 } 352 if (position == Constants.EMPTY_AREA_POSITION_LEFT) { 353 this.mStatusBarLayoutGroupTemplate[0].splice(0, 0, FASlotName.EMPTY); 354 } else if (position == Constants.EMPTY_AREA_POSITION_CENTER) { 355 this.mStatusBarLayoutGroupTemplate[1].splice(0, 0, FASlotName.EMPTY); 356 } else if (position == Constants.EMPTY_AREA_POSITION_RIGHT) { 357 this.mStatusBarLayoutGroupTemplate[2].push(FASlotName.EMPTY); 358 } 359 Log.showInfo(TAG, `setEmptyAreaToLayoutTemplate, template: ${JSON.stringify(this.mStatusBarLayoutGroupTemplate)}`); 360 } 361 362 calcEmptyWidth(rotation: number): void { 363 Log.showInfo(TAG, `calcEmptyWidth, rotation: ${rotation}`); 364 let width = 0; 365 if (this.mConfig.emptyPosition) { 366 if (rotation == 0 || rotation == 180) { 367 width = this.mConfig.emptyPosition.x2 - this.mConfig.emptyPosition.x1; 368 } else { 369 width = this.mConfig.emptyPosition.y2 - this.mConfig.emptyPosition.y1; 370 } 371 } 372 Log.showInfo(TAG, `calcEmptyWidth, width: ${width}`); 373 this.mListener?.setStatusBarEmptyWidth(width); 374 } 375} 376 377let sStatusBarService = createOrGet(StatusBarService, TAG); 378 379export default sStatusBarService;