• 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        this.getWindowProperties(win);
84    }
85
86    /**
87     * Add Listeners
88     *
89     * @param event
90     * @param fn
91     */
92    on(event, fn) {
93        if (Array.isArray(event)) {
94            for (let i = 0, l = event.length; i < l; i++) {
95                this.on(event[i], fn);
96            }
97        } else {
98            (this.events[event] || (this.events[event] = [])).push(fn);
99        }
100    }
101
102    /**
103     * Delete Listeners
104     *
105     * @param event
106     * @param fn
107     */
108    off(event, fn) {
109        if (event == null || event == undefined) {
110            return;
111        }
112        if (Array.isArray(event)) {
113            for (let i = 0, l = event.length; i < l; i++) {
114                this.off(event[i], fn);
115            }
116        }
117        const cbs = this.events[event];
118        if (!cbs) {
119            return;
120        }
121        if (fn == null || fn == undefined) {
122            return;
123        }
124        let cb;
125        let i = cbs.length;
126        while (i--) {
127            cb = cbs[i];
128            if (cb === fn || cb.fn === fn) {
129                cbs.splice(i, 1);
130                break;
131            }
132        }
133    }
134
135    private emit(event, argument: any[]) {
136        let _self = this;
137        if (!this.events[event]) {
138            return;
139        }
140        let cbs = [...this.events[event]];
141        if (cbs) {
142            for (let i = 0, l = cbs.length; i < l; i++) {
143                let ref = cbs[i];
144                if (ref) {
145                    try {
146                        ref.apply(_self, argument);
147                    } catch (e) {
148                        new Error(e);
149                    }
150                }
151            }
152        }
153    }
154
155    private isLeftBlankInitialized(): boolean {
156        return this.leftBlank[0] != 0 || this.leftBlank[1] != 0 || this.leftBlank[2] != 0 || this.leftBlank[3] != 0;
157    }
158
159    // Unit:vp
160    getWinWidth(): number {
161        return px2vp(this.winWidth);
162    }
163
164    // Unit:vp
165    getWinHeight(): number {
166        return px2vp(this.winHeight);
167    }
168
169    getStatusBarHeight(): number {
170        return px2vp(this.statusBarHeight);
171    }
172
173    getNaviBarHeight(): number {
174        return px2vp(this.naviBarHeight);
175    }
176
177    async initWindowMode() {
178        Log.debug(TAG, `start to initialize photos application window mode: ${this.windowMode}`);
179    }
180
181    isSplitMode(): boolean {
182        return (WindowMode.PRIMARY == this.windowMode || WindowMode.SECONDARY == this.windowMode)
183    }
184
185    async checkWindowMode() {
186        let before = this.windowMode;
187        let mode = await globalThis.photosWindowStage.getWindowMode();
188        Log.info(TAG, `photos application before/current window mode: ${before}/${mode}`);
189
190        if (before == mode) {
191            return;
192        }
193        this.windowMode = mode;
194        if (WindowMode.FULL_SCREEN == this.windowMode) {
195            await this.setFullScreen();
196        } else {
197            this.setSplitScreen();
198        }
199    }
200
201    private setMainWindow(win: window.Window) {
202        Log.debug(TAG, 'setMainWindow');
203        win.on('windowSizeChange', (data) => {
204            Log.debug(TAG, `windowSizeChange ${JSON.stringify(data)}`);
205            this.checkWindowMode()
206            this.onWinSizeChanged(data);
207        })
208    }
209
210    private getWindowProperties(win: window.Window) {
211        Log.debug(TAG, 'getWindowProperties');
212        try {
213            let properties = win.getWindowProperties();
214            if(properties.windowRect.width !== 0 && properties.windowRect.height !== 0){
215                this.winWidth = properties.windowRect.width;
216                this.winHeight = properties.windowRect.height;
217            }
218            Log.debug(TAG, `this.winWidth = ${this.winWidth} this.winHeight = ${this.winHeight}`);
219        } catch (exception) {
220            console.error('Failed to obtain the window properties. Cause: ' + JSON.stringify(exception));
221        }
222    }
223
224    private async setFullScreen() {
225        let topWindow: any = AppStorage.Get(WindowConstants.MAIN_WINDOW);
226        Log.debug(TAG, 'getTopWindow start');
227        try {
228            await topWindow.setLayoutFullScreen(true)
229            Log.debug(TAG, 'setFullScreen true Succeeded');
230            await this.hideStatusBar(topWindow);
231        } catch (err) {
232            Log.error(TAG, `setFullScreen err: ${err}`);
233        }
234    }
235
236    setSplitScreen() {
237        try {
238            this.statusBarHeight = 0;
239            this.naviBarHeight = 0;
240            this.leftBlank = [0, 0, 0, 0];
241            AppStorage.SetOrCreate(BroadcastConstants.LEFT_BLANK, this.leftBlank);
242        } catch (err) {
243            Log.error(TAG, `setSplitScreen err: ${err}`);
244        }
245    }
246
247    private async hideStatusBar(topWindow: any) {
248        Log.debug(TAG, 'hideStatusBar start');
249        let names = ['navigation'];
250        Log.debug(TAG, `getTopWindow names: ${names} end`);
251        try {
252            await topWindow.setSystemBarEnable(names)
253            Log.debug(TAG, 'hideStatusBar Succeeded');
254            let data = await topWindow.getAvoidArea(0)
255            Log.debug(TAG, `Succeeded in obtaining the area. Data: ${JSON.stringify(data)}`);
256            this.onLeftBlankChanged(data);
257            let barColor = await getResourceString($r('app.color.default_background_color'));
258            let barContentColor = await getResourceString($r('app.color.default_bar_content_color'));
259            if (!barColor) {
260                barColor = '#00FFFFFF';
261            }
262            if (!barContentColor) {
263                barContentColor = '#FF000000';
264            }
265            await topWindow.setSystemBarProperties({
266                navigationBarColor: barColor,
267                navigationBarContentColor: barContentColor
268            });
269            Log.info(TAG, 'setStatusBarColor done');
270        } catch (err) {
271            Log.error(TAG, `hideStatusBar err: ${err}`);
272        }
273    }
274
275    async setNavigationBarColor(barColor: string, barContentColor: string) {
276        Log.debug(TAG, 'setNavigationBarColor start');
277        let topWindow: any = AppStorage.Get(WindowConstants.MAIN_WINDOW);
278        try {
279            topWindow.setSystemBarProperties(
280                {
281                    navigationBarColor: barColor,
282                    navigationBarContentColor: barContentColor
283                },
284                () => Log.info(TAG, 'setStatusBarColor done')
285            );
286        } catch (err) {
287            Log.error(TAG, `setNavigationBarColor err: ${err}`);
288        }
289    }
290
291    setSystemUi(isShowBar: boolean): void {
292        Log.debug(TAG, 'setSystemUi start');
293        let topWindow: any = AppStorage.Get(WindowConstants.MAIN_WINDOW);
294        Log.debug(TAG, 'getTopWindow start');
295        let names = ["navigation"];
296        if (!isShowBar) {
297            names = [];
298        }
299        Log.debug(TAG, `getTopWindow names: ${names} end`);
300        try {
301            topWindow.setSystemBarEnable(names, () => {
302                Log.debug(TAG, 'setFullScreen Succeeded');
303                if (isShowBar) {
304                    topWindow.getAvoidArea(0, (err, data) => {
305                        Log.info(TAG, 'Succeeded in obtaining the area. Data:' + JSON.stringify(data));
306                        this.onLeftBlankChanged(data);
307                    });
308                }
309            })
310        } catch (err) {
311            Log.error(TAG, `setSystemUi err: ${err}`);
312        }
313    }
314
315    private onLeftBlankChanged(area) {
316        if (area == null || area == undefined || area.bottomRect.height == 0) {
317            return;
318        }
319        let leftBlankBefore = {
320            status: this.statusBarHeight,
321            navi: this.naviBarHeight
322        };
323        this.statusBarHeight = 0;
324        this.naviBarHeight = area.bottomRect.height;
325        this.leftBlank = [this.leftBlank[0], this.leftBlank[1], this.leftBlank[2], area.bottomRect.height];
326        if (leftBlankBefore.status != this.statusBarHeight || leftBlankBefore.navi != this.naviBarHeight) {
327            Log.info(TAG, `leftBlank changed: ${JSON.stringify(leftBlankBefore)}-${JSON.stringify(this.leftBlank)}`)
328            AppStorage.SetOrCreate(BroadcastConstants.LEFT_BLANK, this.leftBlank);
329        }
330    }
331
332    private onWinSizeChanged(size) {
333        Log.info(TAG, `onWinSizeChanged ${JSON.stringify(size)}`);
334        if (size == null || size == undefined) {
335            return;
336        }
337        let sizeBefore = {
338            width: this.winWidth,
339            height: this.winHeight
340        };
341        this.winWidth = size.width;
342        this.winHeight = size.height;
343
344
345        if (sizeBefore.width != this.winWidth || sizeBefore.height != this.winHeight) {
346            Log.info(TAG, `winSize changed: ${JSON.stringify(sizeBefore)} -> ${JSON.stringify(size)}`);
347            this.emit(screenManager.ON_WIN_SIZE_CHANGED, [size]);
348        }
349    }
350
351    private onRotationAngleChanged(angle) {
352        if (angle == null || angle == undefined) {
353            return;
354        }
355
356        if (angle == 0) {
357            this.horizontal = false;
358        } else {
359            this.horizontal = true;
360        }
361        AppStorage.SetOrCreate(SCREEN_ORIENTATION_HORIZONTAL, this.horizontal);
362    }
363
364    isHorizontal(): boolean {
365        if (AppStorage.Get(SCREEN_ORIENTATION_HORIZONTAL) == null) {
366            AppStorage.SetOrCreate(SCREEN_ORIENTATION_HORIZONTAL, this.horizontal);
367        }
368        return AppStorage.Get(SCREEN_ORIENTATION_HORIZONTAL);
369    }
370
371    isSidebar(): boolean {
372        if (AppStorage.Get(SCREEN_SIDEBAR) == null) {
373            AppStorage.SetOrCreate(SCREEN_SIDEBAR, this.sidebar);
374        }
375        return AppStorage.Get(SCREEN_SIDEBAR);
376    }
377
378    getColumnsWidth(count: number): number {
379        let columns = this.getScreenColumns()
380        Log.info(TAG, `getColumnsWidth count is ${count} colunms is ${columns}`);
381        let columnWidth = (px2vp(this.winWidth) - COLUMN_MARGIN) / columns;
382        return columnWidth * count - COLUMN_GUTTER;
383    }
384
385    getScreenColumns(): number {
386        let width = px2vp(this.winWidth)
387        if (width < ScreenWidth.WIDTH_MEDIUM) {
388            return ColumnSize.COLUMN_FOUR;
389        } else if (width >= ScreenWidth.WIDTH_MEDIUM && width < ScreenWidth.WIDTH_LARGE) {
390            return ColumnSize.COLUMN_EIGHT;
391        } else {
392            return ColumnSize.COLUMN_TWELVE;
393        }
394    }
395
396    setKeepScreenOn() {
397        Log.info(TAG, 'setKeepScreenOn start');
398        let topWindow: any = AppStorage.Get('mainWindow');
399        try {
400            topWindow.setKeepScreenOn(true, () => Log.info(TAG, 'setKeepScreenOn Succeeded'))
401        } catch (err) {
402            Log.error(TAG, `setKeepScreenOn err: ${err}`);
403        }
404    }
405
406    setKeepScreenOff() {
407        Log.info(TAG, 'setKeepScreenOff start');
408        let topWindow: any = AppStorage.Get('mainWindow');
409        try {
410            topWindow.setKeepScreenOn(false, () => Log.info(TAG, 'setKeepScreenOff Succeeded'))
411        } catch (err) {
412            Log.error(TAG, `setKeepScreenOff err: ${err}`);
413        }
414    }
415}
416
417let screenManager = createOrGet(ScreenManager, TAG);
418
419export default screenManager as ScreenManager;
420