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