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