• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 */
15import deviceInfo from '@ohos.deviceInfo';
16import window from '@ohos.window';
17import createOrGet from '../utils/SingleInstanceUtils';
18import { Log } from '../utils/Log';
19import { BroadcastConstants } from '../constants/BroadcastConstants';
20import { WindowConstants } from '../constants/WindowConstants';
21import { getResourceString } from '../utils/ResourceUtils';
22
23export enum ColumnSize {
24    COLUMN_TWO = 2,
25    COLUMN_FOUR = 4,
26    COLUMN_SIX = 6,
27    COLUMN_EIGHT = 8,
28    COLUMN_TWELVE = 12
29}
30
31enum ScreenWidth {
32    WIDTH_MEDIUM = 520,
33    WIDTH_LARGE = 840
34}
35
36enum WindowMode {
37    UNDEFINED = 1,
38    FULL_SCREEN,
39    PRIMARY,
40    SECONDARY,
41    FLOATING
42}
43
44const TAG = "ScreenManager"
45
46const APP_KEY_SCREEN_MANAGER = 'app_key_screen_manager';
47
48const SCREEN_ORIENTATION_HORIZONTAL: string = 'isHorizontal';
49const SCREEN_SIDEBAR: string = 'isSidebar';
50
51const COLUMN_MARGIN: number = 12;
52const COLUMN_GUTTER: number = 12;
53
54class ScreenManager {
55    readonly ON_WIN_SIZE_CHANGED = 'on_win_size_changed';
56    readonly ON_LEFT_BLANK_CHANGED = 'on_left_blank_changed';
57    readonly DEFAULT_WIDTH: number = 1920;
58    readonly DEFAULT_HEIGHT: number = 1080;
59    readonly SPLIT_THRESHOLD = 1.7;
60    private winWidth = 0.0;
61    private winHeight = 0.0;
62    private statusBarHeight = 0;
63    private naviBarHeight = 0;
64    private leftBlank: [number, number, number, number] = [0, 0, 0, 0];
65    private events = [];
66    private mainWindow: window.Window = undefined;
67
68    // Default orientation
69    private horizontal = deviceInfo.deviceType == 'phone' || deviceInfo.deviceType == 'default' ? false : true;
70
71    // Default sidebar
72    private sidebar = deviceInfo.deviceType == 'phone' || deviceInfo.deviceType == 'default' ? false : true;
73    private windowMode = WindowMode.UNDEFINED;
74
75    constructor() {
76        Log.info(TAG, 'constructor');
77    }
78
79    async initializationSize(win): Promise<void> {
80        this.mainWindow = win;
81        this.setMainWindow(win)
82        await this.checkWindowMode();
83    }
84
85    /**
86     * Add Listeners
87     *
88     * @param event
89     * @param fn
90     */
91    on(event, fn) {
92        if (Array.isArray(event)) {
93            for (let i = 0, l = event.length; i < l; i++) {
94                this.on(event[i], fn);
95            }
96        } else {
97            (this.events[event] || (this.events[event] = [])).push(fn);
98        }
99    }
100
101    /**
102     * Delete Listeners
103     *
104     * @param event
105     * @param fn
106     */
107    off(event, fn) {
108        if (event == null || event == undefined) {
109            return;
110        }
111        if (Array.isArray(event)) {
112            for (let i = 0, l = event.length; i < l; i++) {
113                this.off(event[i], fn);
114            }
115        }
116        const cbs = this.events[event];
117        if (!cbs) {
118            return;
119        }
120        if (fn == null || fn == undefined) {
121            return;
122        }
123        let cb;
124        let i = cbs.length;
125        while (i--) {
126            cb = cbs[i];
127            if (cb === fn || cb.fn === fn) {
128                cbs.splice(i, 1);
129                break;
130            }
131        }
132    }
133
134    private emit(event, argument: any[]) {
135        let _self = this;
136        if (!this.events[event]) {
137            return;
138        }
139        let cbs = [...this.events[event]];
140        if (cbs) {
141            for (let i = 0, l = cbs.length; i < l; i++) {
142                let ref = cbs[i];
143                if (ref) {
144                    try {
145                        ref.apply(_self, argument);
146                    } catch (e) {
147                        new Error(e);
148                    }
149                }
150            }
151        }
152    }
153
154    private isLeftBlankInitialized(): boolean {
155        return this.leftBlank[0] != 0 || this.leftBlank[1] != 0 || this.leftBlank[2] != 0 || this.leftBlank[3] != 0;
156    }
157
158    // Unit:vp
159    getWinWidth(): number {
160        return px2vp(this.winWidth);
161    }
162
163    // Unit:vp
164    getWinHeight(): number {
165        return px2vp(this.winHeight);
166    }
167
168    getStatusBarHeight(): number {
169        return px2vp(this.statusBarHeight);
170    }
171
172    getNaviBarHeight(): number {
173        return px2vp(this.naviBarHeight);
174    }
175
176    async initWindowMode() {
177        Log.debug(TAG, `start to initialize photos application window mode: ${this.windowMode}`);
178    }
179
180    isSplitMode(): boolean {
181        return (WindowMode.PRIMARY == this.windowMode || WindowMode.SECONDARY == this.windowMode)
182    }
183
184    async checkWindowMode() {
185        let before = this.windowMode;
186        let mode = await globalThis.photosWindowStage.getWindowMode();
187        Log.info(TAG, `photos application before/current window mode: ${before}/${mode}`);
188
189        if (before == mode) {
190            return;
191        }
192        this.windowMode = mode;
193        if (WindowMode.FULL_SCREEN == this.windowMode) {
194            await this.setFullScreen();
195        } else {
196            this.setSplitScreen();
197        }
198    }
199
200    private setMainWindow(win: window.Window) {
201        Log.debug(TAG, 'setMainWindow');
202        win.on('windowSizeChange', (data) => {
203            Log.debug(TAG, `windowSizeChange ${JSON.stringify(data)}`);
204            this.checkWindowMode()
205            this.onWinSizeChanged(data);
206        })
207    }
208
209    private async setFullScreen() {
210        let topWindow: any = AppStorage.Get(WindowConstants.MAIN_WINDOW);
211        Log.debug(TAG, 'getTopWindow start');
212        try {
213            await topWindow.setLayoutFullScreen(true)
214            Log.debug(TAG, 'setFullScreen true Succeeded');
215            await this.hideStatusBar(topWindow);
216        } catch (err) {
217            Log.error(TAG, `setFullScreen err: ${err}`);
218        }
219    }
220
221    setSplitScreen() {
222        try {
223            this.statusBarHeight = 0;
224            this.naviBarHeight = 0;
225            this.leftBlank = [0, 0, 0, 0];
226            AppStorage.SetOrCreate(BroadcastConstants.LEFT_BLANK, this.leftBlank);
227        } catch (err) {
228            Log.error(TAG, `setSplitScreen err: ${err}`);
229        }
230    }
231
232    private async hideStatusBar(topWindow: any) {
233        Log.debug(TAG, 'hideStatusBar start');
234        let names = ['navigation'];
235        Log.debug(TAG, `getTopWindow names: ${names} end`);
236        try {
237            await topWindow.setSystemBarEnable(names)
238            Log.debug(TAG, 'hideStatusBar Succeeded');
239            let data = await topWindow.getAvoidArea(0)
240            Log.debug(TAG, `Succeeded in obtaining the area. Data: ${JSON.stringify(data)}`);
241            this.onLeftBlankChanged(data);
242            let barColor = await getResourceString($r('app.color.default_background_color'));
243            let barContentColor = await getResourceString($r('app.color.default_bar_content_color'));
244            if (!barColor) {
245                barColor = '#00FFFFFF';
246            }
247            if (!barContentColor) {
248                barContentColor = '#FF000000';
249            }
250            await topWindow.setSystemBarProperties({
251                navigationBarColor: barColor,
252                navigationBarContentColor: barContentColor
253            });
254            Log.info(TAG, 'setStatusBarColor done');
255        } catch (err) {
256            Log.error(TAG, `hideStatusBar err: ${err}`);
257        }
258    }
259
260    async setNavigationBarColor(barColor: string, barContentColor: string) {
261        Log.debug(TAG, 'setNavigationBarColor start');
262        let topWindow: any = AppStorage.Get(WindowConstants.MAIN_WINDOW);
263        try {
264            topWindow.setSystemBarProperties(
265                {
266                    navigationBarColor: barColor,
267                    navigationBarContentColor: barContentColor
268                },
269                () => Log.info(TAG, 'setStatusBarColor done')
270            );
271        } catch (err) {
272            Log.error(TAG, `setNavigationBarColor err: ${err}`);
273        }
274    }
275
276    setSystemUi(isShowBar: boolean): void {
277        Log.debug(TAG, 'setSystemUi start');
278        let topWindow: any = AppStorage.Get(WindowConstants.MAIN_WINDOW);
279        Log.debug(TAG, 'getTopWindow start');
280        let names = ["navigation"];
281        if (!isShowBar) {
282            names = [];
283        }
284        Log.debug(TAG, `getTopWindow names: ${names} end`);
285        try {
286            topWindow.setSystemBarEnable(names, () => {
287                Log.debug(TAG, 'setFullScreen Succeeded');
288                if (isShowBar) {
289                    topWindow.getAvoidArea(0, (err, data) => {
290                        Log.info(TAG, 'Succeeded in obtaining the area. Data:' + JSON.stringify(data));
291                        this.onLeftBlankChanged(data);
292                    });
293                }
294            })
295        } catch (err) {
296            Log.error(TAG, `setSystemUi err: ${err}`);
297        }
298    }
299
300    private onLeftBlankChanged(area) {
301        if (area == null || area == undefined || area.bottomRect.height == 0) {
302            return;
303        }
304        let leftBlankBefore = {
305            status: this.statusBarHeight,
306            navi: this.naviBarHeight
307        };
308        this.statusBarHeight = 0;
309        this.naviBarHeight = area.bottomRect.height;
310        this.leftBlank = [this.leftBlank[0], this.leftBlank[1], this.leftBlank[2], area.bottomRect.height];
311        if (leftBlankBefore.status != this.statusBarHeight || leftBlankBefore.navi != this.naviBarHeight) {
312            Log.info(TAG, `leftBlank changed: ${JSON.stringify(leftBlankBefore)}-${JSON.stringify(this.leftBlank)}`)
313            AppStorage.SetOrCreate(BroadcastConstants.LEFT_BLANK, this.leftBlank);
314        }
315    }
316
317    private onWinSizeChanged(size) {
318        Log.info(TAG, `onWinSizeChanged ${JSON.stringify(size)}`);
319        if (size == null || size == undefined) {
320            return;
321        }
322        let sizeBefore = {
323            width: this.winWidth,
324            height: this.winHeight
325        };
326        this.winWidth = size.width;
327        this.winHeight = size.height;
328
329
330        if (sizeBefore.width != this.winWidth || sizeBefore.height != this.winHeight) {
331            Log.info(TAG, `winSize changed: ${JSON.stringify(sizeBefore)} -> ${JSON.stringify(size)}`);
332            this.emit(screenManager.ON_WIN_SIZE_CHANGED, [size]);
333        }
334    }
335
336    private onRotationAngleChanged(angle) {
337        if (angle == null || angle == undefined) {
338            return;
339        }
340
341        if (angle == 0) {
342            this.horizontal = false;
343        } else {
344            this.horizontal = true;
345        }
346        AppStorage.SetOrCreate(SCREEN_ORIENTATION_HORIZONTAL, this.horizontal);
347    }
348
349    isHorizontal(): boolean {
350        if (AppStorage.Get(SCREEN_ORIENTATION_HORIZONTAL) == null) {
351            AppStorage.SetOrCreate(SCREEN_ORIENTATION_HORIZONTAL, this.horizontal);
352        }
353        return AppStorage.Get(SCREEN_ORIENTATION_HORIZONTAL);
354    }
355
356    isSidebar(): boolean {
357        if (AppStorage.Get(SCREEN_SIDEBAR) == null) {
358            AppStorage.SetOrCreate(SCREEN_SIDEBAR, this.sidebar);
359        }
360        return AppStorage.Get(SCREEN_SIDEBAR);
361    }
362
363    getColumnsWidth(count: number): number {
364        let columns = this.getScreenColumns()
365        Log.info(TAG, `getColumnsWidth count is ${count} colunms is ${columns}`);
366        let columnWidth = (px2vp(this.winWidth) - COLUMN_MARGIN) / columns;
367        return columnWidth * count - COLUMN_GUTTER;
368    }
369
370    getScreenColumns(): number {
371        let width = px2vp(this.winWidth)
372        if (width < ScreenWidth.WIDTH_MEDIUM) {
373            return ColumnSize.COLUMN_FOUR;
374        } else if (width >= ScreenWidth.WIDTH_MEDIUM && width < ScreenWidth.WIDTH_LARGE) {
375            return ColumnSize.COLUMN_EIGHT;
376        } else {
377            return ColumnSize.COLUMN_TWELVE;
378        }
379    }
380
381    setKeepScreenOn() {
382        Log.info(TAG, 'setKeepScreenOn start');
383        let topWindow: any = AppStorage.Get('mainWindow');
384        try {
385            topWindow.setKeepScreenOn(true, () => Log.info(TAG, 'setKeepScreenOn Succeeded'))
386        } catch (err) {
387            Log.error(TAG, `setKeepScreenOn err: ${err}`);
388        }
389    }
390
391    setKeepScreenOff() {
392        Log.info(TAG, 'setKeepScreenOff start');
393        let topWindow: any = AppStorage.Get('mainWindow');
394        try {
395            topWindow.setKeepScreenOn(false, () => Log.info(TAG, 'setKeepScreenOff Succeeded'))
396        } catch (err) {
397            Log.error(TAG, `setKeepScreenOff err: ${err}`);
398        }
399    }
400}
401
402let screenManager = createOrGet(ScreenManager, TAG);
403
404export default screenManager as ScreenManager;
405