• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;