• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 */
15
16import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
17import { BusinessError } from '@ohos.base';
18import audio from '@ohos.multimedia.audio';
19import camera from '@ohos.multimedia.camera';
20import { CustomContentDialog } from '@ohos.arkui.advanced.Dialog';
21import { Log, PermissionDialogException, PermissionDialogReturn } from '../common/utils/utils';
22import { GroupInfo, WantInfo } from '../common/model/typedef';
23import { GlobalContext } from '../common/utils/globalContext';
24import Constants from '../common/utils/constant';
25import { globalGroup, groups } from '../common/model/permissionGroup';
26import bundleManager from '@ohos.bundle.bundleManager';
27import { getCallerBundleInfo } from './PermissionStateSheetDialog';
28import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession';
29import common from '@ohos.app.ability.common';
30import { PermissionGroup } from '../common/model/definition';
31
32
33let globalIsOn: boolean;
34let session: UIExtensionContentSession;
35let storage = LocalStorage.getShared();
36let bundleName = '';
37
38@Entry(storage)
39@Component
40struct GlobalSwitchSheetDialog {
41  @LocalStorageLink('want') want: Want | null = storage.get<Want>('want') || null;
42  @LocalStorageLink('session') session: UIExtensionContentSession =
43    storage.get<UIExtensionContentSession>('session') as UIExtensionContentSession;
44  private context = getContext(this) as common.ServiceExtensionContext;
45  private muteSuppoted = false;
46  private groupName: PermissionGroup = PermissionGroup.OTHER;
47  dialogController: CustomDialogController | null = new CustomDialogController({
48    builder: CustomContentDialog({
49      contentBuilder: () => {
50        this.buildDialog();
51      },
52      contentAreaPadding: {left: 0, right: 0}
53    }),
54    offset: { dx: 0, dy: `-${GlobalContext.load('avoidAreaHeight') as string}` }, // unit included in globalContext
55    alignment: DialogAlignment.Bottom,
56    customStyle: false,
57    isModal: true,
58    width: '100%',
59    autoCancel: false,
60    cornerRadius: {
61      topLeft: 32,
62      topRight: 32,
63      bottomLeft: 0,
64      bottomRight: 0
65    },
66    cancel: () => {
67      PermissionDialogReturn([Constants.ERR_GLOBAL_SWITCH_EXCEPTION], session);
68      this.context.terminateSelf();
69      this.dialogController?.close();
70    }
71  });
72
73  @Builder
74  buildDialog() {
75    applicationItem({
76      isMuteSupported: this.muteSuppoted,
77      currentGroup: this.groupName
78    })
79  }
80
81  async aboutToAppear() {
82    session = this.session;
83    Log.info('GlobalSwitchSheetDialog aboutToAppear');
84    Log.info('GlobalSwitchSheetDialog getWant' + JSON.stringify(this.want));
85    let callerBundle = getCallerBundleInfo(this.want as Object as WantInfo);
86    Log.info('GlobalSwitchSheetDialog bundleName ' + callerBundle.bundleName);
87    let globalSwitch = callerBundle.globSwitch;
88    bundleName = callerBundle.bundleName;
89
90    if (globalSwitch === Constants.GLOBAL_SWITCH_CAMERA) {
91      this.groupName = PermissionGroup.CAMERA;
92    } else if (globalSwitch === Constants.GLOBAL_SWITCH_MICROPHONE) {
93      this.groupName = PermissionGroup.MICROPHONE;
94    } else {
95      Log.error('global switch not suppoted');
96      PermissionDialogException(Constants.ERR_GLOBAL_SWITCH_NOT_SUPPORTED, session);
97      this.context.terminateSelf();
98      return;
99    }
100
101    if (this.groupName == 'MICROPHONE') {
102      let audioManager = audio.getAudioManager();
103      let audioVolumeManager = audioManager.getVolumeManager();
104      let groupid = audio.DEFAULT_VOLUME_GROUP_ID;
105      let audioVolumeGroupManager = await audioVolumeManager.getVolumeGroupManager(groupid);
106      this.muteSuppoted = true;
107      globalIsOn = !audioVolumeGroupManager.isPersistentMicMute();
108    } else {
109      let cameraManager = camera.getCameraManager(GlobalContext.load('context'));
110      this.muteSuppoted = cameraManager.isCameraMuteSupported();
111      globalIsOn = !cameraManager.isCameraMuted();
112    }
113
114    if (this.muteSuppoted == false) {
115      Log.error('global switch muted');
116      PermissionDialogException(Constants.ERR_GLOBAL_SWITCH_NOT_SUPPORTED, session);
117      this.context.terminateSelf();
118      return;
119    }
120
121    if (globalIsOn) {
122      Log.error('global switch is on');
123      PermissionDialogException(Constants.ERR_GLOBAL_SWITCH_IS_ON, session);
124      this.context.terminateSelf();
125      return;
126    }
127
128    Log.info('isMuted ' + globalIsOn);
129    this.dialogController?.open();
130  }
131
132  onPageShow(): void {
133    Log.info('GlobalSwitchSheetDialog onPageShow' );
134  }
135
136  build() {
137  }
138}
139
140@CustomDialog
141struct applicationItem {
142  private context = getContext(this) as common.ServiceExtensionContext;
143  @State globalIsOn: boolean = false;
144  @State backTitle: string = '';
145  @State groupInfo: GroupInfo = new GroupInfo(PermissionGroup.OTHER, '', '', '', [], '', [], [], false);
146  @State currentGroup: PermissionGroup = PermissionGroup.OTHER;
147  @State isMuteSupported: boolean = false;
148  @State appName: ResourceStr = '';
149  private controller: CustomDialogController;
150
151  dialogController: CustomDialogController | null = new CustomDialogController({
152    builder: CustomContentDialog({
153      contentBuilder: () => {
154        this.buildContent();
155      },
156      contentAreaPadding: { left: Constants.PADDING_24, right: Constants.PADDING_24 },
157      buttons: [
158        {
159          value: $r('app.string.cancel'),
160          buttonStyle: ButtonStyleMode.TEXTUAL,
161          action: () => {
162            Log.info('global cancel');
163            if (this.dialogController !== null) {
164              this.dialogController.close();
165            }
166          }
167        },
168        {
169          value: $r('app.string.close'),
170          buttonStyle: ButtonStyleMode.TEXTUAL,
171          action: () => {
172            Log.info('global accept');
173            if (this.currentGroup == 'MICROPHONE') {
174              let audioManager = audio.getAudioManager();
175              let audioVolumeManager = audioManager.getVolumeManager();
176              audioVolumeManager.getVolumeGroupManager(audio.DEFAULT_VOLUME_GROUP_ID).then(audioVolumeGroupManager => {
177                audioVolumeGroupManager.setMicMutePersistent(true, audio.PolicyType.PRIVACY).then(() => {
178                  Log.info('microphone muted');
179                  if (this.dialogController !== null) {
180                    this.dialogController.close();
181                  }
182                })
183              })
184            } else {
185              let cameraManager = camera.getCameraManager(this.context);
186              cameraManager.muteCamera(true);
187              if (this.dialogController !== null) {
188                this.dialogController.close();
189              }
190            }
191          }
192        }
193      ],
194    }),
195    autoCancel: false
196  });
197
198  globalListen() {
199    if (this.currentGroup == 'CAMERA') {
200      let cameraManager = camera.getCameraManager(GlobalContext.load('context'));
201      cameraManager.on('cameraMute', (err, curMuted) => {
202        Log.info('curMuted: ' + JSON.stringify(curMuted) + ' err: ' + JSON.stringify(err));
203        this.globalIsOn = !curMuted;
204      })
205    } else {
206      let audioManager = audio.getAudioManager();
207      let audioVolumeManager = audioManager.getVolumeManager();
208      let groupId = audio.DEFAULT_VOLUME_GROUP_ID;
209      audioVolumeManager.getVolumeGroupManager(groupId).then(audioVolumeGroupManager => {
210        audioVolumeGroupManager.on('micStateChange', micStateChange => {
211          Log.info('micStateChange: ' + JSON.stringify(micStateChange));
212          this.globalIsOn = !micStateChange.mute;
213        })
214      })
215    }
216  }
217
218  @Builder
219  buildContent(): void {
220    Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
221      Column() {
222        Text(this.currentGroup == 'CAMERA' ? $r('app.string.close_camera') : $r('app.string.close_microphone'))
223          .fontSize(Constants.TEXT_BIG_FONT_SIZE)
224          .fontColor($r('sys.color.font_primary'))
225          .fontWeight(FontWeight.Medium)
226          .lineHeight(Constants.TEXT_BIG_LINE_HEIGHT)
227          .width(Constants.FULL_WIDTH)
228          .padding({ top: Constants.PADDING_14, bottom: Constants.PADDING_14 })
229        Text(
230          this.currentGroup == 'CAMERA' ?
231          $r('app.string.close_camera_desc') :
232          $r('app.string.close_microphone_desc')
233        )
234          .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
235          .fontColor($r('sys.color.font_primary'))
236          .lineHeight(Constants.TEXT_LINE_HEIGHT)
237      }
238      .clip(true)
239    }
240  }
241
242  /**
243   * Grant permissions to the app
244   * @param {Number} accessTokenId
245   * @param {String} permission permission name
246   * @param {Number} index Array index to modify permission status
247   */
248  grantUserGrantedPermission(accessTokenId: number, permission: Permissions, resolve: (value: number) => void) {
249    abilityAccessCtrl.createAtManager().grantUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG)
250      .then(() => {
251        resolve(0);
252      }).catch((error: BusinessError) => {
253      resolve(-1);
254      Log.error('grantUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
255    })
256  }
257
258  /**
259   * Deauthorize the app
260   * @param {Number} accessTokenId
261   * @param {String} permission permission name
262   * @param {Number} index Array index to modify permission status
263   */
264  revokeUserGrantedPermission(accessTokenId: number, permission: Permissions, resolve: (value: number) => void) {
265    abilityAccessCtrl.createAtManager().revokeUserGrantedPermission(
266      accessTokenId, permission, Constants.PERMISSION_FLAG
267    ).then(() => {
268      resolve(0);
269    }).catch((error: BusinessError) => {
270      resolve(-1);
271      Log.error('revokeUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
272    })
273  }
274
275  /**
276   * Lifecycle function, executed when the page is initialized
277   */
278  async aboutToAppear() {
279    try {
280      let bundleInfo = await bundleManager.getBundleInfo(
281        bundleName,
282        bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
283      let manager = this.context.createBundleContext(bundleName).resourceManager;
284      this.appName = await manager.getStringValue(bundleInfo.appInfo.labelId);
285    } catch (e) {
286      Log.error('get appName failed ' + JSON.stringify(e));
287    }
288    groups.forEach(group => {
289      if (group.name === this.currentGroup) {
290        this.groupInfo = group;
291      }
292    })
293    this.backTitle = this.groupInfo.label;
294    this.globalIsOn = globalIsOn;
295    if (globalGroup.indexOf(this.currentGroup) !== -1) {
296      this.globalListen();
297    }
298  }
299
300  aboutToDisappear() {
301    this.dialogController = null;
302  }
303
304  build() {
305    Column() {
306      Row() {
307        Flex({ alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) {
308          Column() {
309            Column() {
310              Text($r(this.backTitle, this.appName))
311                .align(Alignment.Start)
312                .fontColor($r('sys.color.font_primary'))
313                .maxLines(Constants.MAXIMUM_HEADER_LINES)
314                .textOverflow({ overflow: TextOverflow.Ellipsis })
315                .fontSize(Constants.TEXT_BIG_FONT_SIZE)
316                .flexGrow(Constants.FLEX_GROW)
317                .fontWeight(FontWeight.Bold)
318                .padding({left: Constants.PADDING_10, top: Constants.PADDING_20})
319            }
320            .width(Constants.FULL_WIDTH)
321            .alignItems(HorizontalAlign.Start)
322            if (globalGroup.indexOf(this.currentGroup) !== -1 && this.isMuteSupported === true) {
323              Row() {
324                Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
325                  Text(this.currentGroup == 'CAMERA' ? $r('app.string.camera') : $r('app.string.microphone'))
326                    .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE).fontColor($r('sys.color.font_primary'))
327                    .fontWeight(FontWeight.Medium)
328                  Row() {
329                    Toggle({ type: ToggleType.Switch, isOn: this.globalIsOn })
330                      .selectedColor($r('sys.color.icon_emphasize'))
331                      .switchPointColor($r('sys.color.comp_background_primary_contrary'))
332                      .onChange((isOn: boolean) => {
333                        if (isOn) {
334                          if (this.currentGroup == 'CAMERA') {
335                            let cameraManager = camera.getCameraManager(GlobalContext.load('context'));
336                            cameraManager.muteCamera(false);
337                            PermissionDialogReturn([Constants.PERMISSION_DIALOG_SUCCESS], session);
338                            this.context.terminateSelf();
339                          } else {
340                            let audioManager = audio.getAudioManager();
341                            let audioVolumeManager = audioManager.getVolumeManager();
342                            let groupId = audio.DEFAULT_VOLUME_GROUP_ID;
343                            audioVolumeManager.getVolumeGroupManager(groupId).then(audioVolumeGroupManager => {
344                              audioVolumeGroupManager.setMicMutePersistent(false, audio.PolicyType.PRIVACY);
345                              PermissionDialogReturn([Constants.PERMISSION_DIALOG_SUCCESS], session);
346                              this.context.terminateSelf();
347                            })
348                          }
349                        }
350                      })
351                    Row().onClick(() => {
352                      if (this.dialogController !== null) {
353                        this.dialogController.open();
354                      }
355                    })
356                      .width(Constants.DEFAULT_SLIDER_WIDTH).height(Constants.DEFAULT_SLIDER_HEIGHT)
357                      .position({ x: this.globalIsOn ? 0 : Constants.OFFSET, y: 0 })
358                  }.clip(true)
359                }.height(Constants.LISTITEM_ROW_HEIGHT)
360                .padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
361              }.padding({ top: Constants.LIST_PADDING_TOP, bottom: Constants.LIST_PADDING_BOTTOM })
362              .backgroundColor($r('sys.color.comp_background_list_card'))
363              .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
364              .margin({ top: Constants.MARGIN_16 })
365            }
366          }.padding({ left: Constants.AUTHORITY_LISTITEM_PADDING_LEFT })
367        }.flexGrow(Constants.FLEX_GROW)
368      }
369    }
370  }
371}