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