• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2023 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 { backBar } from '../common/components/backBar';
17import { alphabetIndexerComponent } from '../common/components/alphabeticalIndex';
18import { textInput } from '../common/components/search';
19import router from '@ohos.router';
20import bundleManager from '@ohos.bundle.bundleManager';
21import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
22import { BusinessError } from '@ohos.base';
23import audio from '@ohos.multimedia.audio'
24import camera from '@ohos.multimedia.camera'
25import { CustomContentDialog } from '@ohos.arkui.advanced.Dialog';
26import { Log, verifyAccessToken, indexValue, sortByName } from '../common/utils/utils';
27import { ApplicationObj, GroupInfo, RouterParams1, PermissionApplications, AppInfo } from '../common/model/typedef';
28import { GlobalContext } from '../common/utils/globalContext';
29import { Permission, PermissionGroup } from '../common/model/definition';
30import Constants from '../common/utils/constant';
31import { polymorphismGroup, globalGroup, groups } from '../common/model/permissionGroup';
32
33const locationStatus: Resource[] = [
34  $r('app.string.always_allow'),
35  $r('app.string.ban'),
36  $r('app.string.per_inquiry'),
37  $r('app.string.allowed_only_during_use')
38];
39let globalIsOn: boolean = (router.getParams() as RouterParams1).globalIsOn; // return title name
40
41@Entry
42@Component
43struct locationInfoPage {
44  private backTitle: ResourceStr = (router.getParams() as RouterParams1).backTitle;
45  private list: PermissionApplications[] = (router.getParams() as RouterParams1).list;
46  @State currentGroup: PermissionGroup = GlobalContext.load('currentPermissionGroup');
47  @State polymorphismIsOn: Array<number> = [];
48  @State folderStatusArray: Array<Array<boolean>> = [[]];
49
50  build() {
51    GridRow({ gutter: Constants.GUTTER, columns: {
52      xs: Constants.XS_COLUMNS, sm: Constants.SM_COLUMNS, md: Constants.MD_COLUMNS, lg: Constants.LG_COLUMNS } }) {
53      GridCol({
54        span: { xs: Constants.XS_SPAN, sm: Constants.SM_SPAN, md: Constants.MD_SPAN, lg: Constants.LG_SPAN },
55        offset: { xs: Constants.XS_OFFSET, sm: Constants.SM_OFFSET, md: Constants.MD_OFFSET, lg: Constants.LG_OFFSET }
56      }) {
57        Row() {
58          Column() {
59            Row() {
60              backBar({ title: JSON.stringify(this.backTitle), recordable: false })
61            }
62            Row() {
63              Column() {
64                applicationItem({ polymorphismIsOn: $polymorphismIsOn, folderStatusArray: $folderStatusArray })
65
66              }.width(Constants.FULL_WIDTH)
67            }
68            .layoutWeight(Constants.LAYOUT_WEIGHT)
69          }
70        }
71        .height(Constants.FULL_HEIGHT)
72        .width(Constants.FULL_WIDTH)
73        .backgroundColor($r('sys.color.background_secondary'))
74      }
75    }.backgroundColor($r('sys.color.background_secondary'))
76  }
77
78  onPageShow() {
79    if (polymorphismGroup.indexOf(this.currentGroup) !== -1) {
80      let bundleNames: string[] = [];
81      this.list.forEach(permissionManager => {
82        permissionManager.bundleNames.forEach(bundleName => {
83          if (bundleNames.indexOf(bundleName) == -1) {
84            bundleNames.push(bundleName);
85          }
86        })
87      })
88
89      bundleNames.forEach((bundleName, index) => {
90        bundleManager.getBundleInfo(
91          bundleName,
92          bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION |
93          bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION
94        ).then(res => {
95          this.getGroupStatus(res, index);
96        }).catch((error: BusinessError) => {
97          Log.error(bundleName + 'onPageShow getBundleInfo failed, cause: ' + JSON.stringify(error));
98        })
99      })
100    }
101  }
102
103  getGroupStatus(res: bundleManager.BundleInfo, index: number) {
104    this.polymorphismIsOn[index] = Constants.PERMISSION_BAN;
105    this.folderStatusArray[index] = [false, false, false];
106    let reqPermissions: string[] = [];
107    res.reqPermissionDetails.forEach(item => {
108      reqPermissions.push(item.name);
109    })
110    let acManager = abilityAccessCtrl.createAtManager();
111    if (this.currentGroup === 'LOCATION' && reqPermissions.includes(Permission.APPROXIMATELY_LOCATION)) {
112      try {
113        let fuzzyState = acManager.verifyAccessTokenSync(res.appInfo.accessTokenId, Permission.APPROXIMATELY_LOCATION);
114        fuzzyState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
115          this.polymorphismIsOn[index] = Constants.PERMISSION_ALLOWED_ONLY_DURING_USE : null;
116        let backgroundState =
117          acManager.verifyAccessTokenSync(res.appInfo.accessTokenId, Permission.LOCATION_IN_BACKGROUND);
118        backgroundState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
119          this.polymorphismIsOn[index] = Constants.PERMISSION_ALLOW : null;
120        acManager.getPermissionFlags(res.appInfo.accessTokenId, Permission.APPROXIMATELY_LOCATION ).then(flag => {
121          flag === Constants.PERMISSION_ALLOW_THIS_TIME ?
122            this.polymorphismIsOn[index] = Constants.PERMISSION_ONLY_THIS_TIME : null;
123        })
124      } catch (err) {
125        Log.error('change location status error: ' + JSON.stringify(err));
126      }
127    }
128    if (this.currentGroup === 'FOLDER') {
129      for (let j = 0; j < this.list.length; j++) {
130        if (reqPermissions.indexOf(this.list[j].permission) == -1) {
131          continue;
132        }
133        let access = acManager.verifyAccessTokenSync(res.appInfo.accessTokenId, this.list[j].permission);
134        if (Number(access) === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
135          this.updateFolderStatus(index, j);
136        }
137      }
138    }
139  }
140
141  updateFolderStatus(index: number, idx: number) {
142    switch (this.list[idx].permission) {
143      case Permission.READ_WRITE_DOWNLOAD_DIRECTORY:
144        this.folderStatusArray[index][0] = true;
145        break;
146      case Permission.READ_WRITE_DESKTOP_DIRECTORY:
147        this.folderStatusArray[index][1] = true;
148        break;
149      case Permission.READ_WRITE_DOCUMENTS_DIRECTORY:
150        this.folderStatusArray[index][2] = true;
151        break;
152    }
153  }
154}
155
156@Component
157struct applicationItem {
158  private backTitle: ResourceStr = (router.getParams() as RouterParams1).backTitle;
159  private list: PermissionApplications[] = (router.getParams() as RouterParams1).list;
160  @State permissionNum: number = Constants.PERMISSION_NUM; // permission num
161  @State toggleIsOn: boolean[] = []; // toggle switch state array
162  @State isRisk: boolean[] = [];
163  @State isFirst: boolean[] = [];
164  @State applicationList: ApplicationObj[] = []; // application info array
165  @State searchResult: boolean = true; // search results
166  @Link polymorphismIsOn: Array<number>;
167  @Link folderStatusArray: Array<Array<boolean>>;
168  @State globalIsOn: boolean = true;
169  @State selectedIndex: number = 0;
170  @State isTouch: string = '';
171  @State groupInfo: GroupInfo = new GroupInfo(PermissionGroup.OTHER, '', '', '', [], '', [], [], false);
172  @State currentGroup: PermissionGroup = GlobalContext.load('currentPermissionGroup');
173  @State isMuteSupported: boolean = GlobalContext.load('isMuteSupported');
174  @State allBundleInfo: AppInfo[] = GlobalContext.load('allBundleInfo');
175  scroller: Scroller = new Scroller();
176
177  dialogController: CustomDialogController | null = new CustomDialogController({
178    builder: CustomContentDialog({
179      contentBuilder: () => {
180        this.buildContent();
181      },
182      contentAreaPadding: { left: Constants.PADDING_24, right: Constants.PADDING_24 },
183      buttons: [
184        {
185          value: $r('app.string.cancel'),
186          buttonStyle: ButtonStyleMode.TEXTUAL,
187          action: () => {
188            Log.info('global cancel');
189            this.dialogController?.close();
190          }
191        },
192        {
193          value: $r('app.string.close'),
194          buttonStyle: ButtonStyleMode.TEXTUAL,
195          action: () => {
196            Log.info('global accept');
197            if (this.currentGroup == PermissionGroup.MICROPHONE) {
198              let audioManager = audio.getAudioManager();
199              let audioVolumeManager = audioManager?.getVolumeManager();
200              audioVolumeManager?.getVolumeGroupManager(audio.DEFAULT_VOLUME_GROUP_ID).then(audioVolumeGroupManager => {
201                audioVolumeGroupManager.setMicMutePersistent(true, audio.PolicyType.PRIVACY).then(() => {
202                  this.dialogController?.close();
203                })
204              })
205            } else {
206              let cameraManager = camera.getCameraManager(GlobalContext.load('context'));
207              cameraManager?.muteCameraPersistent(true, camera.PolicyType.PRIVACY);
208              this.dialogController?.close();
209            }
210          }
211        }
212      ],
213    }),
214    autoCancel: false
215  });
216
217  @Builder
218  buildContent(): void {
219    Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
220      Column() {
221        Text(this.currentGroup == 'CAMERA' ? $r('app.string.close_camera') : $r('app.string.close_microphone'))
222          .fontSize(Constants.TEXT_BIG_FONT_SIZE)
223          .fontColor($r('sys.color.font_primary'))
224          .fontWeight(FontWeight.Medium)
225          .lineHeight(Constants.TEXT_BIG_LINE_HEIGHT)
226          .width(Constants.FULL_WIDTH)
227          .padding({ top: Constants.PADDING_14, bottom: Constants.PADDING_14 })
228        Text(
229          this.currentGroup == 'CAMERA' ?
230          $r('app.string.close_camera_desc') :
231          $r('app.string.close_microphone_desc')
232        )
233          .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
234          .fontColor($r('sys.color.font_primary'))
235          .lineHeight(Constants.TEXT_LINE_HEIGHT)
236      }
237      .clip(true)
238    }
239  }
240
241  @Builder ListItemLayout(item: ApplicationObj) {
242    ListItem() {
243      Row() {
244        Column() {
245          Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
246            Row() {
247              Image(item.icon)
248                .objectFit(ImageFit.Contain)
249                .width(Constants.AUTHORITY_IMAGE_WIDTH)
250                .height(Constants.AUTHORITY_IMAGE_HEIGHT)
251                .draggable(false)
252                .margin({ right: Constants.AUTHORITY_IMAGE_MARGIN_RIGHT })
253              Column() {
254                Text(item.label)
255                  .width(Constants.MAXIMUM_HEADER_WIDTH)
256                  .maxLines(Constants.MAXIMUM_HEADER_LINES)
257                  .textOverflow({ overflow: TextOverflow.Ellipsis })
258                  .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
259                  .fontWeight(FontWeight.Medium)
260                  .fontColor($r('sys.color.font_primary'))
261                if (this.isRisk[item.index]) {
262                  Text($r('app.string.risk_warning'))
263                    .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
264                    .fontColor($r('sys.color.font_secondary'))
265                }
266              }.flexGrow(Constants.FLEX_GROW)
267              .alignItems(HorizontalAlign.Start)
268              if (polymorphismGroup.indexOf(this.currentGroup) == -1) {
269                Toggle({ type: ToggleType.Switch, isOn: this.toggleIsOn[item.index] })
270                  .selectedColor($r('sys.color.icon_emphasize'))
271                  .switchPointColor($r('sys.color.comp_background_primary_contrary'))
272                  .padding({ right: 0 })
273                  .width(Constants.AUTHORITY_TOGGLE_WIDTH)
274                  .height(Constants.AUTHORITY_TOGGLE_HEIGHT)
275                  .onChange((isOn: boolean) => {
276                    if (item.permission === undefined) {
277                      return;
278                    }
279                    if (this.isFirst[item.index] && isOn) {
280                      this.isFirst[item.index] = false;
281                      return;
282                    }
283                    this.isFirst[item.index] = false;
284                    let _this = this;
285                    if (isOn) {
286                      let promises = this.list.map(it => new Promise<number>((resolve) => {
287                        _this.grantUserGrantedPermission(item.accessTokenId, it.permission, resolve);
288                      }));
289                      Promise.all(promises).then(() => {
290                        _this.toggleIsOn[item.index] = true;
291                        let num = _this.toggleIsOn.filter(item => item === true).length;
292                        _this.permissionNum = num;
293                      });
294                    } else {
295                      let promises = this.list.map(it => new Promise<number>((resolve) => {
296                        _this.revokeUserGrantedPermission(item.accessTokenId, it.permission, resolve);
297                      }));
298                      Promise.all(promises).then(() => {
299                        _this.toggleIsOn[item.index] = false;
300                        let num = _this.toggleIsOn.filter(item => item === true).length;
301                        _this.permissionNum = num;
302                      });
303                    }
304                  })
305              } else {
306                if (this.currentGroup === 'FOLDER') {
307                  Text() {
308                    if (this.folderStatusArray[item.index].includes(true)) {
309                      ForEach(this.folderStatusArray[item.index], (status: boolean, index) =>{
310                        if (status) {
311                          if (index !== this.folderStatusArray[item.index].indexOf(true)) {
312                            Span($r('app.string.separator'))
313                          }
314                          Span(index === 0 ? $r('app.string.Download') : index === 1 ? $r('app.string.Desktop') : $r('app.string.Document'))
315                        }
316                      })
317                    } else {
318                      Span($r('app.string.ban'))
319                    }
320                  }
321                    .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
322                    .fontColor($r('sys.color.font_secondary'))
323                    .margin({ right: Constants.AUTHORITY_IMAGE_MARGIN_RIGHT })
324                } else {
325                  Text(locationStatus[this.polymorphismIsOn[item.index]])
326                    .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
327                    .fontColor($r('sys.color.font_secondary'))
328                    .margin({ right: Constants.AUTHORITY_IMAGE_MARGIN_RIGHT })
329                }
330                SymbolGlyph($r('sys.symbol.chevron_forward'))
331                  .width(Constants.IMAGE_WIDTH)
332                  .height(Constants.IMAGE_HEIGHT)
333                  .fontSize(Constants.FONT_SIZE_18_vp)
334                  .fontColor([$r('sys.color.icon_tertiary')])
335                  .fontWeight(FontWeight.Medium)
336              }
337            }
338            .width(Constants.FULL_WIDTH)
339            .height(Constants.AUTHORITY_ROW_HEIGHT)
340            .constraintSize({ minHeight: Constants.AUTHORITY_CONSTRAINTSIZE_MINHEIGHT })
341          }
342        }.onClick(() => {
343          if (polymorphismGroup.indexOf(this.currentGroup) !== -1) {
344            let permissions: string[] = [];
345            this.list.forEach(data => {
346              if (data.bundleNames.includes(item.bundleName as string)) {
347                permissions.push(data.permission);
348              }
349            })
350            this.allBundleInfo.forEach(bundleInfo => {
351              if (bundleInfo.bundleName === item.bundleName) {
352                GlobalContext.store('applicationInfo', bundleInfo);
353              }
354            })
355            GlobalContext.store('folderStatus', this.folderStatusArray[item.index]);
356            GlobalContext.store('locationStatus', this.polymorphismIsOn[item.index]);
357            router.pushUrl({
358              url: 'pages/application-tertiary',
359              params: {
360                bundleName: item.bundleName,
361                backTitle: this.backTitle,
362                permission: permissions,
363                status: Constants.PERMISSION_BAN,
364                tokenId: item.accessTokenId
365              }
366            });
367          }
368        })
369      }
370    }.padding({ left: $r('sys.float.ohos_id_card_margin_start'), right: $r('sys.float.ohos_id_card_margin_end') })
371    .enabled(!this.isRisk[item.index])
372    .opacity(this.isRisk[item.index] ? $r('sys.float.ohos_id_alpha_disabled') : 1)
373    .borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
374    .linearGradient((this.isTouch === item.bundleName) ? {
375        angle: 90,
376        direction: GradientDirection.Right,
377        colors: [['#DCEAF9', 0.0], ['#FAFAFA', 1.0]]
378      } : {
379        angle: 90,
380        direction: GradientDirection.Right,
381        colors: [[$r('sys.color.comp_background_list_card'), 1], [$r('sys.color.comp_background_list_card'), 1]]
382      })
383    .onTouch(event => {
384      if (event === undefined) {
385        return;
386      }
387      if (event.type === TouchType.Down && polymorphismGroup.indexOf(this.currentGroup) !== -1) {
388        this.isTouch = item.bundleName ? item.bundleName : '';
389      }
390      if (event.type === TouchType.Up) {
391        this.isTouch = '';
392      }
393    })
394  }
395
396  /**
397   * Take the total number of access applications
398   */
399  getGrantApplicationNumber() {
400    if (polymorphismGroup.indexOf(this.currentGroup) !== -1) {
401      if (this.currentGroup === 'FOLDER') {
402        let sum = this.folderStatusArray.filter(item => item.includes(true));
403        return sum.length;
404      } else {
405        let sum = this.polymorphismIsOn.filter(
406          item => item !== Constants.PERMISSION_BAN && item !== Constants.PERMISSION_ONLY_THIS_TIME
407        );
408        return sum.length;
409      }
410    } else {
411      return this.permissionNum;
412    }
413  }
414
415  /**
416   * Grant permissions to the app
417   * @param {Number} accessTokenId
418   * @param {String} permission permission name
419   * @param {Number} index Array index to modify permission status
420   */
421  grantUserGrantedPermission(accessTokenId: number, permission: Permissions, resolve: (value: number) => void) {
422    abilityAccessCtrl.createAtManager().grantUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG)
423    .then(() => {
424      resolve(0);
425    }).catch((error: BusinessError) => {
426      resolve(-1);
427      Log.error('grantUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
428    })
429  }
430
431  /**
432   * Deauthorize the app
433   * @param {Number} accessTokenId
434   * @param {String} permission permission name
435   * @param {Number} index Array index to modify permission status
436   */
437  revokeUserGrantedPermission(accessTokenId: number, permission: Permissions, resolve: (value: number) => void) {
438    abilityAccessCtrl.createAtManager().revokeUserGrantedPermission(
439      accessTokenId, permission, Constants.PERMISSION_FLAG
440    ).then(() => {
441      resolve(0);
442    }).catch((error: BusinessError) => {
443      resolve(-1);
444      Log.error('revokeUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
445    })
446  }
447
448  /**
449   * Lifecycle function, executed when the page is initialized
450   */
451  aboutToAppear() {
452    let bundleNames: string[] = [];
453    this.applicationList = [];
454    this.list.forEach(permissionManager => {
455      permissionManager.bundleNames.forEach(bundleName => {
456        if (bundleNames.indexOf(bundleName) == -1) {
457          bundleNames.push(bundleName);
458        }
459      })
460    })
461    groups.forEach(group => {
462      if (group.name === this.currentGroup) {
463        this.groupInfo = group;
464      }
465    })
466
467    for (let i = 0; i < bundleNames.length; i++) {
468      // Get BundleInfo based on bundle name
469      this.allBundleInfo.forEach(bundleInfo => {
470        if (bundleInfo.bundleName === bundleNames[i]) {
471          this.getApplicationList(bundleInfo, i);
472        }
473      })
474    }
475
476    if (globalGroup.indexOf(this.currentGroup) !== -1) {
477      this.globalListen();
478    }
479  }
480
481  aboutToDisappear() {
482    this.dialogController = null;
483  }
484
485  getApplicationList(bundleInfo: AppInfo, i: number) {
486    this.applicationList.push(
487      new ApplicationObj(
488        bundleInfo.label,
489        bundleInfo.icon,
490        i,
491        bundleInfo.tokenId,
492        this.list[0].permission,
493        bundleInfo.zhTag,
494        bundleInfo.indexTag,
495        bundleInfo.language,
496        bundleInfo.bundleName) // Get the first letter in the returned initials array
497    );
498    this.isRisk[i] = false;
499    try {
500      abilityAccessCtrl.createAtManager().getPermissionFlags(bundleInfo.tokenId, this.list[0].permission)
501        .then(data => {
502          if (data == Constants.PERMISSION_POLICY_FIXED) {
503            this.isRisk[i] = true;
504          }
505        })
506    } catch (err) {
507      Log.error('getPermissionFlags error: ' + JSON.stringify(err));
508    }
509    // 0: have permission; -1: no permission
510    let boole = true;
511    this.permissionNum++;
512    for (let j = 0; j < this.list.length; j++) {
513      if (bundleInfo.permissions.indexOf(this.list[j].permission) == -1) {
514        continue;
515      }
516      verifyAccessToken(bundleInfo.tokenId, this.list[j].permission).then((access) => {
517        if (Number(access) === Constants.PERMISSION_INDEX) {
518          if (boole) {
519            this.toggleIsOn[i] = true;
520            this.isFirst[i] = true;
521          }
522        } else {
523          if (boole) {
524            this.permissionNum--;
525          }
526          boole = false;
527          this.toggleIsOn[i] = false;
528          this.isFirst[i] = false;
529        }
530      });
531    }
532  }
533
534  globalListen() {
535    this.globalIsOn = globalIsOn;
536    if (this.currentGroup == 'CAMERA') {
537      let cameraManager = camera.getCameraManager(GlobalContext.load('context'));
538      cameraManager.on('cameraMute', (err, curMuted) => {
539        Log.info('curMuted: ' + JSON.stringify(curMuted) + ' err: ' + JSON.stringify(err));
540        this.globalIsOn = !curMuted;
541      })
542    } else {
543      let audioManager = audio.getAudioManager();
544      let audioVolumeManager = audioManager.getVolumeManager();
545      let groupId = audio.DEFAULT_VOLUME_GROUP_ID;
546      audioVolumeManager.getVolumeGroupManager(groupId).then(audioVolumeGroupManager => {
547        audioVolumeGroupManager.on('micStateChange', micStateChange => {
548          let muteState = audioVolumeGroupManager.isPersistentMicMute();
549          Log.info('micStateChange: ' + JSON.stringify(muteState));
550          this.globalIsOn = !muteState;
551        })
552      })
553    }
554  }
555
556  build() {
557    Column() {
558      Row() {
559        textInput({
560          applicationItem: $applicationList,
561          searchResult: $searchResult
562        })
563      }.padding({
564        left: Constants.AUTHORITY_TEXTINPUT_PADDING_LEFT,
565        right: Constants.AUTHORITY_TEXTINPUT_PADDING_RIGHT
566      })
567      Flex({ alignItems:ItemAlign.Start, justifyContent: FlexAlign.Start }) {
568        Column() {
569          if (globalGroup.indexOf(this.currentGroup) !== -1 && this.isMuteSupported === true) {
570            Row() {
571              Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
572                Text(this.currentGroup == 'CAMERA' ? $r('app.string.camera') : $r('app.string.microphone'))
573                  .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE).fontColor($r('sys.color.font_primary'))
574                  .fontWeight(FontWeight.Medium)
575                Row() {
576                  Toggle({ type: ToggleType.Switch, isOn: this.globalIsOn })
577                    .selectedColor($r('sys.color.icon_emphasize'))
578                    .switchPointColor($r('sys.color.comp_background_primary_contrary'))
579                    .padding({ right: 0 })
580                    .onChange((isOn: boolean) => {
581                      if (isOn) {
582                        if (this.currentGroup == 'CAMERA') {
583                          let cameraManager = camera.getCameraManager(GlobalContext.load('context'));
584                          cameraManager.muteCameraPersistent(false, camera.PolicyType.PRIVACY);
585                        } else {
586                          let audioManager = audio.getAudioManager();
587                          let audioVolumeManager = audioManager.getVolumeManager();
588                          let groupId = audio.DEFAULT_VOLUME_GROUP_ID;
589                          audioVolumeManager.getVolumeGroupManager(groupId).then(audioVolumeGroupManager => {
590                            audioVolumeGroupManager.setMicMutePersistent(false, audio.PolicyType.PRIVACY);
591                          })
592                        }
593                      }
594                    })
595                  Row().onClick(() => {
596                    this.dialogController?.open();
597                  })
598                    .width(Constants.DEFAULT_SLIDER_WIDTH).height(Constants.DEFAULT_SLIDER_HEIGHT)
599                    .position({ x: this.globalIsOn ? 0 : Constants.OFFSET, y: 0 })
600                }.clip(true)
601              }.height(Constants.LISTITEM_ROW_HEIGHT)
602              .padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
603            }.padding({ top: Constants.LIST_PADDING_TOP, bottom: Constants.LIST_PADDING_BOTTOM })
604            .backgroundColor($r('sys.color.comp_background_list_card'))
605            .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
606            .margin({ top: Constants.TERTIARY_ROW_MARGIN_TOP })
607          }
608          Flex({ justifyContent: FlexAlign.Start }) {
609            if (this.globalIsOn) {
610              if (this.getGrantApplicationNumber() > 0) {
611                Text(
612                  this.groupInfo.enableDescription ?
613                  $r(this.groupInfo.enableDescription, String(this.getGrantApplicationNumber())) :
614                  ''
615                )
616                  .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
617                  .fontColor($r('sys.color.font_secondary'))
618                  .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP })
619              } else {
620                Text(this.groupInfo.forbiddenDescription)
621                  .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
622                  .fontColor($r('sys.color.font_secondary'))
623                  .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP })
624              }
625            } else {
626              Text(
627                this.currentGroup == 'CAMERA' ?
628                $r('app.string.camera_is_off') :
629                $r('app.string.microphone_is_off')
630              )
631                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
632                .fontColor($r('sys.color.font_secondary'))
633                .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP })
634            }
635          }.padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
636          .margin({ bottom: Constants.AUTHORITY_ROW_MARGIN_BOTTOM })
637          Row() {
638            Column() {
639              if (!this.applicationList.length) {
640                if (this.searchResult) {
641                  Row() {}
642                } else {
643                  Row() {
644                    Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
645                      Image($r('app.media.searchnoresult'))
646                        .objectFit(ImageFit.Contain)
647                        .width(Constants.SEARCHNORESULT_IMAGE_WIDTH)
648                        .height(Constants.SEARCHNORESULT_IMAGE_HEIGHT)
649                        .draggable(false)
650                    }
651                  }
652                }
653              } else {
654                Row() {
655                  List({ scroller: this.scroller }) {
656                    ForEach(sortByName(this.applicationList), (item: ApplicationObj) => {
657                      this.ListItemLayout(item)
658                    }, (item: ApplicationObj) => JSON.stringify(item))
659                  }
660                  .backgroundColor($r('sys.color.comp_background_list_card'))
661                  .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
662                  .padding(Constants.LIST_PADDING_TOP)
663                  .divider({
664                    strokeWidth: Constants.DIVIDER,
665                    color: $r('sys.color.comp_divider'),
666                    startMargin: Constants.DIVIDER_MARGIN_RIGHT_APPLICATION,
667                    endMargin: Constants.DEFAULT_MARGIN_END
668                  })
669                  .onScrollIndex((start, end) => {
670                    GlobalContext.getContext().set('scroller', this.scroller);
671                    if (this.applicationList.length > 0) {
672                      let alphabeticalIndex: string = sortByName(this.applicationList)[start].indexTag;
673                      let index = indexValue.indexOf(alphabeticalIndex);
674                      this.selectedIndex = index >= 0 ? index : 0;
675                    }
676                  })
677                }
678              }
679            }.width(Constants.FULL_WIDTH)
680            .margin({
681              bottom: globalGroup.includes(this.currentGroup) && this.isMuteSupported === true ?
682                Constants.AUTHORITY_LIST_MARGIN_BOTTOM_GLOBAL :
683                Constants.AUTHORITY_LIST_MARGIN_BOTTOM
684            })
685          }
686        }.padding({ left: Constants.AUTHORITY_LISTITEM_PADDING_LEFT })
687        Column() {
688          alphabetIndexerComponent({ applicationItem: $applicationList, index: $selectedIndex })
689        }.width(Constants.AUTHORITY_ALPHABETINDEX_WIDTH)
690         .padding({ top: Constants.AUTHORITY_ALPHABETINDEX_PADDING_TOP })
691        .margin({ bottom: Constants.APPLICATION_LIST_MARGIN_BOTTOM })
692      }.flexGrow(Constants.FLEX_GROW)
693    }.height(Constants.FULL_HEIGHT)
694  }
695}
696