1/**
2 * Copyright (c) 2024 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 window from '@ohos.window';
17import display from '@ohos.display';
18import { Log } from '../utils/Log';
19
20const TAG = 'DisplayManager: ';
21
22export class DisplayManager {
23  private readonly MAIN_WINDOW_PREFIX = 'customMainWindow_';
24  private readonly DEFAULT_MAIN_WINDOW_PAGE = 'pages/SubDisplayWallpaperPage';
25
26  public defaultDisplay: display.Display = undefined;
27  private displayDevices: Array<display.Display> = [];
28
29  private constructor() {
30    Log.showInfo(TAG, 'constructor called.');
31    this.loadDefaultDisplay();
32    this.loadAllDisplays();
33
34    this.initDisplayChangeListener();
35  }
36
37  public static getInstance(): DisplayManager {
38    return globalThis.DisplayManager ??= new DisplayManager();
39  }
40
41  private loadDefaultDisplay() {
42    try {
43      this.defaultDisplay = display.getDefaultDisplaySync();
44      Log.showInfo(TAG, 'loadDefaultDisplay. defaultDisplay id: ' + this.defaultDisplay?.id);
45    } catch (err) {
46      Log.showError(TAG, 'loadDefaultDisplay occur error. errInfo: ' + JSON.stringify(err));
47    }
48  }
49
50  private async loadAllDisplays() {
51    let displays: Array<display.Display> = await display.getAllDisplays();
52    for (let display of displays) {
53      if (this.displayDevices.findIndex(item => item.id === display.id) < 0) {
54        Log.showInfo(TAG, 'new display added. detail: ' + JSON.stringify(display));
55        this.displayDevices.push(display);
56        this.createMainWindow(display);
57      }
58    }
59  }
60
61  private initDisplayChangeListener() {
62    display.on('add', displayId => {
63      Log.showInfo(TAG, 'add new display. id: ' + JSON.stringify(displayId));
64      this.loadAllDisplays();
65    })
66
67    display.on('remove', displayId => {
68      Log.showInfo(TAG, 'remove display. id: ' + JSON.stringify(displayId));
69      let delIndex: number = this.displayDevices.findIndex(item => item.id === displayId);
70      if (delIndex > 0) {
71        this.destroyMainWindow(displayId);
72        this.displayDevices.splice(delIndex, 1);
73      }
74    })
75  }
76
77  /**
78   * 在指定屏幕上创建主window(新屏幕插入时,默认桌面窗口,不支持隐藏;屏幕拔出时,隐藏销毁本窗口)
79   * @param display
80   */
81  private createMainWindow(display: display.Display) {
82    if (display.id === this.defaultDisplay?.id) {
83      //主屏不需要创建主窗口
84      return;
85    }
86    window.createWindow({
87      ctx: globalThis.desktopContext,
88      name: this.MAIN_WINDOW_PREFIX + display.id,
89      windowType: window.WindowType.TYPE_DESKTOP,
90      displayId: display.id
91    }).then((resultWindow: window.Window) => {
92      resultWindow.resize(display.width, display.height);
93      resultWindow.setWindowMode(window.WindowMode.FULLSCREEN);
94      resultWindow.setUIContent(this.DEFAULT_MAIN_WINDOW_PAGE);
95      Log.showInfo(TAG, `create main window ${display.id} success.`);
96
97      resultWindow.showWithAnimation();
98    }).catch(err => {
99      Log.showError(TAG, 'create main window failed. reason: ' + JSON.stringify(err));
100    })
101  }
102
103  private findWindow(displayId: number): window.Window {
104    let resultWindow = undefined;
105    try {
106      resultWindow = window.findWindow(this.MAIN_WINDOW_PREFIX + displayId);
107    } catch (err) {
108      Log.showError(TAG, 'findWindow occur err. errInfo: ' + JSON.stringify(err));
109    }
110    return resultWindow;
111  }
112
113
114  private destroyMainWindow(displayId: number) {
115    if (displayId === this.defaultDisplay?.id) {
116      return;
117    }
118    let resultWindow = this.findWindow(displayId);
119    if (resultWindow?.isWindowShowing()) {
120      resultWindow.hideWithAnimation();
121    }
122    resultWindow?.destroyWindow();
123    Log.showInfo(TAG, `destroy main window ${displayId} success.`);
124  }
125
126  public destroySubDisplayWindow() {
127    for (let display of this.displayDevices) {
128      this.destroyMainWindow(display.id);
129    }
130    display.off('add');
131    display.off('remove');
132  }
133}