1/* 2 * Copyright (c) 2022-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 */ 15import deviceManager from '@ohos.distributedHardware.deviceManager'; 16import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession'; 17import deviceInfo from '@ohos.deviceInfo'; 18import Constant from '../common/constant'; 19import common from '@ohos.app.ability.common'; 20import display from '@ohos.display'; 21import mediaQuery from '@ohos.mediaquery'; 22import i18n from '@ohos.i18n'; 23import { KeyCode } from '@ohos.multimodalInput.keyCode'; 24 25let dmClass: deviceManager.DeviceManager | null; 26let TAG = '[DeviceManagerUI:ConfirmDialog]==>'; 27const ACTION_ALLOW_AUTH_ONCE: number = 0; 28const ACTION_CANCEL_AUTH: number = 1; 29const ACTION_AUTH_CONFIRM_TIMEOUT: number = 2; 30const ACTION_ALLOW_AUTH_ALWAYS: number = 6; 31const MSG_CANCEL_CONFIRM_SHOW: number = 5; 32const DEVICE_TYPE_2IN1: number = 0xA2F; 33const DEVICE_TYPE_PC: number = 0x0C; 34const CAST_PKG_NAME: string = 'CastEngineService'; 35 36@CustomDialog 37struct ConfirmCustomDialog { 38 @State peerAppOperation: string = ''; 39 @State peerCustomDescription: string = ''; 40 @State peerDeviceName: string = ''; 41 @State peerDeviceType: number = 0; 42 @State secondsNum: number = 30; 43 @State times: number = 0; 44 @State isAvailableType: boolean = false; 45 @State btnColor: ResourceColor = Color.Transparent; 46 @State title: string = ''; 47 controller?: CustomDialogController; 48 isPC: boolean = false; 49 50 aboutToAppear() { 51 console.log(TAG + 'aboutToAppear execute PinCustomDialog') 52 let context = getContext() as common.UIAbilityContext; 53 54 if (AppStorage.get('deviceName') != null) { 55 this.peerDeviceName = AppStorage.get('deviceName') as string; 56 console.log('peerDeviceName is ' + this.peerDeviceName); 57 } 58 let customDescriptionStr: string = AppStorage.get('customDescriptionStr') as string; 59 let hostPkgLabel: string = AppStorage.get('hostPkgLabel') as string; 60 if (hostPkgLabel === CAST_PKG_NAME) { 61 this.title = 62 context.resourceManager.getStringSync($r('app.string.dm_confirm_title_cast').id, this.peerDeviceName); 63 } else if (hostPkgLabel != null) { 64 this.title = context.resourceManager.getStringSync($r('app.string.dm_confirm_title_hap').id, hostPkgLabel, 65 this.peerDeviceName); 66 this.peerCustomDescription = context.resourceManager.getStringSync($r('app.string.dm_confirm_intention').id); 67 if (customDescriptionStr != undefined && customDescriptionStr != '') { 68 this.peerCustomDescription = this.peerDeviceName + customDescriptionStr; 69 } 70 } else { 71 let titleFirst: string = 72 context.resourceManager.getStringSync($r('app.string.dm_connect_device').id, this.peerDeviceName); 73 this.title = 74 context.resourceManager.getStringSync($r('app.string.dm_is_trust_device').id, titleFirst); 75 this.peerCustomDescription = context.resourceManager.getStringSync($r('app.string.dm_confirm_intention').id); 76 } 77 78 if (AppStorage.get('deviceType') != null) { 79 this.peerDeviceType = AppStorage.get('deviceType') as number; 80 console.log('peerDeviceType is ' + this.peerDeviceType); 81 } 82 83 this.times = setInterval(() => { 84 console.info('devicemanagerui confirm dialog run seconds:' + this.secondsNum); 85 this.secondsNum--; 86 if (this.secondsNum === 0) { 87 clearInterval(this.times); 88 this.times = 0; 89 this.setUserOperation(ACTION_AUTH_CONFIRM_TIMEOUT); 90 this.destruction(); 91 console.info('click cancel times run out'); 92 } 93 }, 1000) 94 console.log(TAG + 'deviceInfo.deviceType:' + deviceInfo.deviceType); 95 this.isPC = Constant.isPC(); 96 } 97 98 onAllowOnce() { 99 console.log('allow once') 100 if (dmClass == null) { 101 console.log('createDeviceManager is null') 102 return 103 } 104 105 console.log('allow once' + ACTION_ALLOW_AUTH_ONCE) 106 this.setUserOperation(ACTION_ALLOW_AUTH_ONCE) 107 this.destruction() 108 } 109 110 onAllowAlways() { 111 console.log('allow always') 112 if (dmClass == null) { 113 console.log('createDeviceManager is null') 114 return 115 } 116 117 console.log('allow always' + ACTION_ALLOW_AUTH_ALWAYS) 118 this.setUserOperation(ACTION_ALLOW_AUTH_ALWAYS) 119 this.destruction() 120 } 121 122 onCancel() { 123 console.log('cancel') 124 if (dmClass == null) { 125 console.log('createDeviceManager is null') 126 return 127 } 128 129 console.log('cancel' + ACTION_CANCEL_AUTH) 130 this.setUserOperation(ACTION_CANCEL_AUTH) 131 this.destruction() 132 } 133 134 setUserOperation(operation: number) { 135 console.log(TAG + 'setUserOperation: ' + operation) 136 if (dmClass == null) { 137 console.log(TAG + 'setUserOperation: ' + 'dmClass null') 138 return; 139 } 140 try { 141 dmClass.setUserOperation(operation, 'extra'); 142 } catch (error) { 143 console.log(TAG + 'dmClass setUserOperation failed') 144 } 145 } 146 147 destruction() { 148 let session = AppStorage.get<UIExtensionContentSession>('ConfirmSession'); 149 if (session) { 150 session.terminateSelf(); 151 } 152 } 153 154 getImages(peerdeviceType: number): Resource { 155 console.info('peerdeviceType is ' + peerdeviceType); 156 if (peerdeviceType === deviceManager.DeviceType.SPEAKER) { 157 this.isAvailableType = true; 158 return $r('sys.symbol.soundai_fill'); 159 } else if (peerdeviceType === deviceManager.DeviceType.PHONE) { 160 this.isAvailableType = true; 161 return $r('sys.symbol.phone_fill_1'); 162 } else if (peerdeviceType === deviceManager.DeviceType.TABLET) { 163 this.isAvailableType = true; 164 return $r('sys.symbol.pad_fill'); 165 } else if (peerdeviceType === deviceManager.DeviceType.WEARABLE) { 166 this.isAvailableType = true; 167 return $r('sys.symbol.earphone_case_16896'); 168 } else if (peerdeviceType === deviceManager.DeviceType.CAR) { 169 this.isAvailableType = true; 170 return $r('sys.symbol.car_fill'); 171 } else if (peerdeviceType === deviceManager.DeviceType.TV) { 172 this.isAvailableType = true; 173 return $r('sys.symbol.smartscreen_fill'); 174 } else if (peerdeviceType === DEVICE_TYPE_PC) { 175 this.isAvailableType = true; 176 return $r('sys.symbol.matebook_fill'); 177 } else if (peerdeviceType === DEVICE_TYPE_2IN1) { 178 this.isAvailableType = true; 179 return $r('sys.symbol.matebook_fill'); 180 } else { 181 this.isAvailableType = false; 182 return $r('sys.symbol.unknown_device_fill'); 183 } 184 } 185 186 @Builder 187 Symbol() { 188 Shape() { 189 Circle() 190 .width(32) 191 .height(32) 192 .fill($r('sys.color.ohos_id_color_activated')) 193 Column() { 194 SymbolGlyph(this.getImages(this.peerDeviceType)) 195 .fontSize('20vp') 196 .renderingStrategy(SymbolRenderingStrategy.MULTIPLE_OPACITY) 197 .fontColor([$r('sys.color.ohos_id_color_primary_contrary')]) 198 .offset({ x: 6, y: 6 }) 199 } 200 } 201 .visibility(this.isAvailableType ? Visibility.Visible : Visibility.None) 202 .margin({ bottom: 16, top: 24 }) 203 } 204 205 private isTibetanLanguages(): boolean { 206 console.info(`${TAG} isTibetanLanguages in`); 207 let locale = new Intl.Locale(i18n.System.getSystemLanguage()).toString(); 208 console.info(`${TAG} isTibetanLanguages: ${locale}`); 209 return Constant.TIBETAN_LANGUAGES.includes(locale); 210 } 211 212 build() { 213 GridRow({ 214 columns: { xs: 4, sm: 8, md: this.isPC ? 24 : 12 }, 215 gutter: { x: 4 }, 216 breakpoints: { value: ['600vp', '840vp'] } 217 }) { 218 GridCol({ span: { xs: 4, sm: 4, md: this.isPC ? 6 : 4 }, offset: { sm: 2, md: this.isPC ? 9 : 4 } }) { 219 Column() { 220 this.Symbol(); 221 Column() { 222 Text(this.title) 223 .textAlign(TextAlign.Center) 224 .fontSize($r('sys.float.ohos_id_text_size_dialog_tittle')) 225 .fontWeight(FontWeight.Bold) 226 .fontColor($r('sys.color.ohos_id_color_text_primary')) 227 .minFontSize(12) 228 .maxFontSize($r('sys.float.ohos_id_text_size_dialog_tittle')) 229 .heightAdaptivePolicy(TextHeightAdaptivePolicy.LAYOUT_CONSTRAINT_FIRST) 230 .lineHeight(this.isTibetanLanguages() ? 22 : 0) 231 .textOverflow({ overflow: TextOverflow.Ellipsis }) 232 .width('auto') 233 .maxLines(2) 234 Text(this.peerCustomDescription) 235 .textAlign(TextAlign.Start) 236 .fontColor($r('sys.color.ohos_id_color_text_secondary')) 237 .fontWeight(FontWeight.Regular) 238 .textOverflow({ overflow: TextOverflow.Ellipsis }) 239 .fontSize($r('sys.float.ohos_id_text_size_body2')) 240 .maxLines(2) 241 .width('auto') 242 .lineHeight(this.isTibetanLanguages() ? 22 : 0) 243 .margin({ top: 8 }) 244 .visibility(this.peerCustomDescription === '' ? Visibility.None : Visibility.Visible) 245 }.margin({ 246 top: this.isAvailableType ? 0 : 24, 247 bottom: 16, left: 24, right: 24 }) 248 249 Column() { 250 Button($r('app.string.dm_allow_always')) 251 .margin({ bottom: 4 }) 252 .onClick(() => { 253 this.onAllowAlways(); 254 }) 255 .fontColor($r('sys.color.ohos_id_color_text_primary_activated')) 256 .height(this.isTibetanLanguages() ? 'auto' : 40) 257 .width(this.isPC ? 250 : '100%') 258 .backgroundColor(this.btnColor) 259 .onHover((isHover?: boolean, event?: HoverEvent): void => { 260 if (isHover) { 261 this.btnColor = $r('sys.color.ohos_id_color_hover'); 262 } else { 263 this.btnColor = this.isPC ? $r('sys.color.ohos_id_color_button_normal') : Color.Transparent; 264 } 265 }) 266 .stateStyles({ 267 pressed: { 268 .backgroundColor($r('sys.color.ohos_id_color_click_effect')) 269 }, 270 normal: { 271 .backgroundColor(this.isPC ? $r('sys.color.ohos_id_color_button_normal') : Color.Transparent) 272 } 273 }) 274 Button($r('app.string.dm_allow_temp')) 275 .margin({ bottom: 4 }) 276 .onClick(() => { 277 this.onAllowOnce(); 278 }) 279 .fontColor($r('sys.color.ohos_id_color_text_primary_activated')) 280 .height(this.isTibetanLanguages() ? 'auto' : 40) 281 .width(this.isPC ? 250 : '100%') 282 .backgroundColor(this.btnColor) 283 .onHover((isHover?: boolean, event?: HoverEvent): void => { 284 if (isHover) { 285 this.btnColor = $r('sys.color.ohos_id_color_hover'); 286 } else { 287 this.btnColor = this.isPC ? $r('sys.color.ohos_id_color_button_normal') : Color.Transparent; 288 } 289 }) 290 .stateStyles({ 291 pressed: { 292 .backgroundColor($r('sys.color.ohos_id_color_click_effect')) 293 }, 294 normal: { 295 .backgroundColor(this.isPC ? $r('sys.color.ohos_id_color_button_normal') : Color.Transparent) 296 } 297 }) 298 Button($r('app.plural.dm_not_allow', this.secondsNum, this.secondsNum)) 299 .margin({ left: 16, right: 16 }) 300 .fontColor($r('sys.color.ohos_id_color_text_primary_activated')) 301 .defaultFocus(true) 302 .onKeyEvent((event?: KeyEvent) => { 303 if (event && event?.keyCode === KeyCode.KEYCODE_HOME && event?.type === KeyType.Down) { 304 console.log(TAG + 'onKeyEvent eventType: ' + event?.type) 305 return; 306 } 307 if (event && event?.keyCode === KeyCode.KEYCODE_HOME && event?.type === KeyType.Up) { 308 console.log(TAG + 'onKeyEvent eventType: ' + event?.type) 309 this.onCancel(); 310 } 311 }) 312 .onClick(() => { 313 this.onCancel(); 314 }) 315 .height(this.isTibetanLanguages() ? 'auto' : 40) 316 .width(this.isPC ? 250 : '100%') 317 .backgroundColor(this.btnColor) 318 .onHover((isHover?: boolean, event?: HoverEvent): void => { 319 if (isHover) { 320 this.btnColor = $r('sys.color.ohos_id_color_hover'); 321 } else { 322 this.btnColor = this.isPC ? $r('sys.color.ohos_id_color_button_normal') : Color.Transparent; 323 } 324 }) 325 .stateStyles({ 326 pressed: { 327 .backgroundColor($r('sys.color.ohos_id_color_click_effect')) 328 }, 329 normal: { 330 .backgroundColor(this.isPC ? $r('sys.color.ohos_id_color_button_normal') : Color.Transparent) 331 } 332 }) 333 } 334 .margin({ 335 left: 16, 336 right: 16, 337 bottom: this.isPC ? 24 : 8 338 }) 339 } 340 .borderRadius($r('sys.float.ohos_id_corner_radius_dialog')) 341 .backgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THICK) 342 .margin({ left: $r('sys.float.ohos_id_dialog_margin_start'), right: $r('sys.float.ohos_id_dialog_margin_end') }) 343 } 344 }.constraintSize({ maxHeight: '90%' }) 345 } 346} 347 348@Entry 349@Component 350struct dialogPlusPage { 351 dialogController: CustomDialogController = new CustomDialogController({ 352 builder: ConfirmCustomDialog(), 353 autoCancel: false, 354 onWillDismiss: ()=>{ 355 this.onWillDismiss() 356 }, 357 alignment: DialogAlignment.Center, 358 offset: { dx: 0, dy: -20 }, 359 customStyle: true, 360 maskColor: $r('sys.color.ohos_id_color_mask_thin') 361 }); 362 363 initStatue() { 364 if (dmClass) { 365 console.log(TAG + 'deviceManager exist') 366 return 367 } 368 deviceManager.createDeviceManager('com.ohos.devicemanagerui.confirm', 369 (err: Error, dm: deviceManager.DeviceManager) => { 370 if (err) { 371 console.log('createDeviceManager err:' + JSON.stringify(err) + ' --fail:' + JSON.stringify(dm)) 372 return 373 } 374 dmClass = dm 375 dmClass.on('uiStateChange', (data: Record<string, string>) => { 376 console.log('uiStateChange executed, dialog closed' + JSON.stringify(data)) 377 let tmpStr: Record<string, number> = JSON.parse(data.param) 378 let msg: number = tmpStr.uiStateMsg as number 379 if (msg === MSG_CANCEL_CONFIRM_SHOW) { 380 console.log('cancel confirm show.') 381 this.destruction() 382 return 383 } 384 }) 385 }) 386 } 387 388 onWillDismiss() { 389 console.log(TAG + 'onWillDismiss: ' + ACTION_CANCEL_AUTH) 390 this.setUserOperation(ACTION_CANCEL_AUTH); 391 this.destruction(); 392 } 393 394 setUserOperation(operation: number) { 395 console.log(TAG + 'setUserOperation: ' + operation) 396 if (dmClass == null) { 397 console.log(TAG + 'setUserOperation: ' + 'dmClass null') 398 return; 399 } 400 try { 401 dmClass.setUserOperation(operation, 'extra'); 402 } catch (error) { 403 console.log(TAG + 'dmClass setUserOperation failed') 404 } 405 } 406 407 onPageShow() { 408 console.log('onPageShow') 409 this.initStatue() 410 } 411 412 destruction() { 413 let session = AppStorage.get<UIExtensionContentSession>('ConfirmSession'); 414 if (session) { 415 session.terminateSelf(); 416 } 417 } 418 419 aboutToDisappear() { 420 console.log(TAG + 'aboutToDisappear aboutToDisappear') 421 if (dmClass != null) { 422 try { 423 dmClass.off('uiStateChange'); 424 dmClass.release(); 425 } catch (error) { 426 console.log('dmClass release failed') 427 } 428 dmClass = null 429 } 430 } 431 432 build() { 433 Column(this.dialogController.open()) 434 } 435}