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