• 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 */
15import bundleManager from '@ohos.bundle.bundleManager';
16import Constants from '../common/utils/constant';
17import common from '@ohos.app.ability.common';
18import { BusinessError } from '@ohos.base';
19import {
20  checkPermissionGroup,
21  getGroupIdByPermission, getPermissionLabel, Log,
22  PermissionDialogException,
23  PermissionDialogReturn,
24  verifyAccessToken } from '../common/utils/utils';
25import { AppInfo, CallerBundleInfo,
26  CheckboxInfo,
27  MediaDocObj,
28  WantInfo } from '../common/model/typedef';
29import { GlobalContext } from '../common/utils/globalContext';
30import { Permission, PermissionGroup } from '../common/model/definition';
31import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
32import { groups, showSubPermissionsGroup } from '../common/model/permissionGroup';
33import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession';
34import { CustomContentDialog } from '@ohos.arkui.advanced.Dialog'
35
36let storage = LocalStorage.getShared();
37let accessTokenId: number = 0;
38let session: UIExtensionContentSession;
39let results: Map<string, number> = new Map();
40let terminating: boolean = false;
41
42export function ReportDialogResult(wantPermissions: Permissions[]) {
43  let resultArray: number[] = [];
44  Log.info('processed result:' + JSON.stringify(results));
45  for (const permission of wantPermissions) {
46    // check if corresponding result is set
47    if (results.has(permission)) {
48      resultArray.push(results.get(permission)!);
49    } else {
50      Log.error(permission + ' is not processed!');
51      resultArray.push(Constants.ERR_PERMISSION_GRANT_EXCEPTION);
52    }
53  }
54  Log.info('terminating session with return array ' + JSON.stringify(resultArray));
55  PermissionDialogReturn(resultArray, session);
56}
57
58export function getCallerBundleInfo(want: WantInfo): CallerBundleInfo {
59  let bundleName: string = want.parameters['ohos.aafwk.param.callerBundleName'];
60  let uId: number = want.parameters['ohos.aafwk.param.callerUid'] ?? 0;
61  let token: number = want.parameters['ohos.aafwk.param.callerToken'] ?? 0;
62  let permissions: Permissions[] = want.parameters['ohos.user.setting.permission'];
63  let globSwitch: number = want.parameters['ohos.user.setting.global_switch'];
64
65  const callerBundle: CallerBundleInfo = {
66    bundleName: bundleName,
67    uId: uId,
68    permissionGroup: permissions,
69    token: token,
70    globSwitch: globSwitch
71  }
72
73  return callerBundle;
74}
75
76@Entry(storage)
77@Component
78struct PermissionStateSheetDialog {
79  private context = getContext(this) as common.ServiceExtensionContext;
80  @LocalStorageLink('want') want: Want | null = storage.get<Want>('want') || null;
81  @LocalStorageLink('session') session: UIExtensionContentSession =
82    storage.get<UIExtensionContentSession>('session') as UIExtensionContentSession;
83  @State applicationInfo: AppInfo | undefined = undefined;
84  @State folderStatus: boolean[] = [false, false, false];
85  @State reqUserPermissions: Permission[] = [];
86  @State bundleName: string = '';
87  @State isGranted: number = Constants.PERMISSION_ALLOW;
88  @State groupName: ResourceStr = '';
89  @State currentGroup: PermissionGroup = PermissionGroup.OTHER;
90
91  dialogController: CustomDialogController | null = new CustomDialogController({
92    builder: CustomContentDialog({
93      contentBuilder: () => {
94        this.buildDialog();
95      },
96      contentAreaPadding: {left: 0, right: 0}
97    }),
98    offset: { dx: 0, dy: `-${GlobalContext.load('avoidAreaHeight') as string}` }, // unit included in globalContext
99    alignment: DialogAlignment.Bottom,
100    customStyle: false,
101    isModal: true,
102    width: '100%',
103    autoCancel: false,
104    cornerRadius: {topLeft: 32, topRight: 32, bottomLeft: 0, bottomRight: 0},
105    cancel: () => {
106      ReportDialogResult(this.reqUserPermissions);
107      this.context.terminateSelf();
108      this.dialogController?.close();
109    }
110  });
111
112  @Builder
113  buildDialog() {
114    mediaDocumentItem({
115      bundleName: this.bundleName,
116      backTitle: this.groupName,
117      permissions: this.reqUserPermissions,
118      status: this.isGranted,
119      tokenId: this.applicationInfo?.tokenId,
120      applicationInfo: this.applicationInfo,
121      currentGroup: this.currentGroup
122    })
123  }
124
125  build() {
126
127  }
128
129  async aboutToAppear() {
130    session = this.session;
131    await this.GetAppInfo();
132
133    if (!this.applicationInfo) {
134      this.context.terminateSelf();
135    }
136
137    if (this.dialogController !== null && terminating == false) {
138      this.dialogController.open();
139    }
140  }
141
142  async getSpecifiedApplication(bundleName: string): Promise<AppInfo | undefined> {
143    const flag =
144      bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION |
145      bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION;
146    let promise = new Promise<AppInfo | undefined>(async (resolve, reject) => {
147      try {
148        let info = await this.getBundleInfo(bundleName, flag);
149        resolve(info);
150      } catch (e) {
151        resolve(undefined);
152      }
153    })
154    return promise;
155  }
156
157  async getBundleInfo(bundleName: string, flag: number): Promise<AppInfo | undefined> {
158    return new Promise<AppInfo | undefined>(async (resolve, reject) => {
159      let info: AppInfo | undefined = undefined;
160      let permissionGrantMap: Map<string, number> = new Map();
161      let bundleInfo = await bundleManager.getBundleInfo(bundleName, flag);
162      let appPermissions = bundleInfo.reqPermissionDetails;
163      let granted = bundleInfo.permissionGrantStates;
164      info = new AppInfo(bundleInfo.name, bundleInfo.targetVersion,
165        bundleInfo.appInfo.accessTokenId, '', bundleInfo.appInfo.iconId, bundleInfo.appInfo.iconResource,
166        '', bundleInfo.appInfo.labelId, bundleInfo.appInfo.labelResource, [], [], '', '', ''
167      );
168      resolve(info);
169      // check if all permissions passed from want has been claimed by app config
170      for (const wantPermission of this.reqUserPermissions) {
171        if (terminating) {
172          continue;
173        }
174        let idx = appPermissions.findIndex((item) => {
175          return item.name == wantPermission;
176        });
177        if (idx == -1) {
178          Log.error('permission ' + wantPermission + ' not claimed by ' + this.bundleName + ' in module.json');
179          PermissionDialogException(Constants.ERR_PERMISSIONS_NOT_IN_CONFIG, session);
180          terminating = true;
181          this.context.terminateSelf();
182          return;
183        }
184        permissionGrantMap.set(appPermissions[idx].name, granted[idx]);
185      }
186      // check if all permissions are already granted
187      let permissionsAllGranted = true;
188      for (const key of permissionGrantMap.keys()) {
189        if (permissionGrantMap.get(key) === -1) { // -1 means not granted
190          permissionsAllGranted = false;
191        }
192      }
193      // check if all permissions are already granted
194      if (permissionsAllGranted) {
195        Log.error('terminating : ' + terminating + ' requested permissions are all already granted');
196        if (terminating == false) {
197          PermissionDialogException(Constants.ERR_PERMISSIONS_ALL_GRANTED, session);
198          terminating = true;
199          this.context.terminateSelf();
200        }
201      }
202    })
203  }
204
205  aboutToDisappear() {
206    Log.info('permission dialog about to disappear');
207    this.dialogController = null;
208  }
209
210  async GetAppInfo() {
211    let callerBundle: CallerBundleInfo = getCallerBundleInfo(this.want as Object as WantInfo);
212    this.bundleName = callerBundle.bundleName;
213    this.reqUserPermissions = callerBundle.permissionGroup as Permission[]; // user permission is passed from wantInfo
214    // check if wanted permissions are in the same permission group
215    let groupName = checkPermissionGroup(this.reqUserPermissions);
216    if (groupName == null) {
217      terminating = true;
218      PermissionDialogException(Constants.ERR_PERMISSIONS_NOT_SAME_GROUP, session);
219      this.context.terminateSelf();
220    }
221    this.currentGroup = groupName!;
222    // check app infos, check if permissions are claimed , check if permissions are granted
223    this.applicationInfo = await this.getSpecifiedApplication(callerBundle.bundleName);
224    if (this.applicationInfo === undefined) {
225      Log.error('application info is undefined');
226    }
227    // get application detailed info
228    await this.initApplicationInfo(this.applicationInfo!);
229    // initialize permission states
230    await this.initialPermissions();
231    // store application info after initialization is done
232    GlobalContext.store('applicationInfo', this.applicationInfo);
233  }
234
235  async initApplicationInfo(info: AppInfo) {
236    Log.info('labelResource: ' + JSON.stringify(info.labelResource));
237    let resourceManager = this.context.createBundleContext(info.bundleName).resourceManager;
238
239    if (info.labelResource.id !== 0) {
240      info.label = await this.context.resourceManager.getStringValue(info.labelResource);
241    } else {
242      info.label = await resourceManager.getStringValue(info.labelId);
243    }
244
245    try {
246      if (info.iconResource.id !== 0) {
247        let iconDescriptor = this.context.resourceManager.getDrawableDescriptor(info.iconResource);
248        info.icon = iconDescriptor?.getPixelMap();
249      } else {
250        let iconDescriptor = resourceManager.getDrawableDescriptor(info.iconId);
251        info.icon = iconDescriptor?.getPixelMap();
252      }
253    } catch (error) {
254      Log.error(`getDrawableDescriptor failed, error code: ${error.code}, message: ${error.message}.`);
255    }
256
257    if (!info.icon) {
258      info.icon = $r('app.media.icon');
259    }
260
261    let groupIds: number[] = [];
262    for (let i = 0; i < this.reqUserPermissions.length; i++) {
263      let groupId = getGroupIdByPermission(this.reqUserPermissions[i]);
264      if (groupIds.indexOf(groupId) == -1) {
265        groupIds.push(groupId);
266      }
267    }
268    info.permissions = this.reqUserPermissions;
269    info.groupId = groupIds;
270  }
271
272  async getStatus(groupReqPermissions: Permissions[], group: string) {
273    if (group === 'LOCATION') {
274      try {
275        let acManager = abilityAccessCtrl.createAtManager();
276        let fuzzyState = acManager.verifyAccessTokenSync(
277          this.applicationInfo?.tokenId, Permission.APPROXIMATELY_LOCATION
278        );
279        fuzzyState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
280          this.isGranted = Constants.PERMISSION_ALLOWED_ONLY_DURING_USE : null;
281        let backgroundState =
282          acManager.verifyAccessTokenSync(this.applicationInfo?.tokenId, Permission.LOCATION_IN_BACKGROUND);
283        backgroundState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
284          this.isGranted = Constants.PERMISSION_ALLOW : null;
285        await acManager.getPermissionFlags(this.applicationInfo?.tokenId, Permission.APPROXIMATELY_LOCATION )
286        .then(flag => {
287          flag === Constants.PERMISSION_ALLOW_THIS_TIME ? this.isGranted = Constants.PERMISSION_ONLY_THIS_TIME : null;
288        })
289      } catch (err) {
290        Log.error('change location status error: ' + JSON.stringify(err));
291      }
292      GlobalContext.store('locationStatus', this.isGranted);
293      return true;
294    }
295    for (let i = 0; i < groupReqPermissions.length; i++) {
296      let permission = groupReqPermissions[i];
297      let res = await verifyAccessToken(this.applicationInfo!.tokenId, permission);
298      if (res != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
299        this.isGranted = Constants.PERMISSION_BAN;
300      }
301      if (group === 'FOLDER' && res === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
302        switch (permission) {
303          case Permission.READ_WRITE_DOWNLOAD_DIRECTORY:
304            this.folderStatus[0] = true;
305            break;
306          case Permission.READ_WRITE_DESKTOP_DIRECTORY:
307            this.folderStatus[1] = true;
308            break;
309          case Permission.READ_WRITE_DOCUMENTS_DIRECTORY:
310            this.folderStatus[2] = true;
311            break;
312        }
313      }
314    }
315    return true;
316  }
317
318  /**
319   * Initialize permission status information and group permission information
320   */
321  async initialPermissions() {
322    if (this.bundleName && !this.applicationInfo?.groupId.length) {
323      await this.initApplicationInfo(this.applicationInfo!);
324    }
325    let reqPermissions = this.applicationInfo!.permissions;
326    let reqGroupIds = this.applicationInfo!.groupId;
327
328    for (let i = 0; i < reqGroupIds.length; i++) {
329      let id = reqGroupIds[i];
330      let groupName = groups[id].groupName;
331      let group = groups[id].name;
332      let groupReqPermissions: Permissions[] = [];
333
334      for (let j = 0; j < reqPermissions.length; j++) {
335        let permission = reqPermissions[j];
336        if (groups[id].permissions.indexOf(permission) != -1) {
337          groupReqPermissions.push(permission);
338          this.groupName = groupName;
339        }
340      }
341      this.isGranted = group === 'LOCATION' ? Constants.PERMISSION_BAN : Constants.PERMISSION_ALLOW;
342      this.folderStatus = [false, false, false];
343      await this.getStatus(groupReqPermissions, group);
344
345      GlobalContext.store('folderStatus', this.folderStatus);
346    }
347  }
348}
349
350@CustomDialog
351struct mediaDocumentItem {
352  private context = getContext(this) as common.UIAbilityContext;
353  private backTitle: ResourceStr = '';
354  private bundleName: string = '';
355  private permissions: Permission[] = [];
356  private status: number = 0;
357  private tokenId: number = 0;
358  private controller: CustomDialogController;
359  @State hidden: boolean = false;
360  @State currentGroup: PermissionGroup = PermissionGroup.OTHER;
361  @State applicationInfo: AppInfo = GlobalContext.load('applicationInfo');
362  @State folderStatus: boolean[] = [];
363  @State mediaDocListItem: MediaDocObj[] = []; // Permission information array
364  @State selected: number = 0;
365  @State accurateIsOn: boolean = true;
366  @State api: number = 0;
367  @State isRisk: boolean = false; // Whether it is a risky application
368  @State noForeground: boolean = false;
369  @State isTouch: number = -1;
370  @State isCheck: string = '';
371  @State reason: string = '';
372  @State label: string = '';
373  @State version: string = '';
374  @State permissionLabels: Array<ResourceStr> = [];
375  @LocalStorageLink('bundleInfo') bundleInfo: Want = {} as Want;
376
377  /**
378   * Grant permissions to the app
379   * @param {Number} accessTokenId
380   * @param {String} permission permission name
381   */
382  async grantUserGrantedPermission(accessTokenId: number, permission: Permissions) {
383    Log.info('granting permission ' + permission);
384    try {
385      await abilityAccessCtrl.createAtManager()
386        .grantUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG);
387        Log.info('grantUserGrantedPermission ' + permission + ' success.');
388        results.set(permission, Constants.PERMISSION_DIALOG_SUCCESS);
389    } catch (e) {
390        results.set(permission, Constants.ERR_PERMISSION_GRANT_EXCEPTION);
391        Log.error('grantUserGrantedPermission failed. Cause: ' + JSON.stringify(e));
392    }
393  }
394
395  /**
396   * Deauthorize the app
397   * @param {Number} accessTokenId
398   * @param {String} permission permission name
399   */
400  async revokeUserGrantedPermission(accessTokenId: number, permission: Permissions, flag: number) {
401    abilityAccessCtrl.createAtManager().revokeUserGrantedPermission(accessTokenId, permission, flag)
402      .then(() => {
403        Log.error('revokeUserGrantedPermission ' + permission + ' success');
404      })
405      .catch((error: BusinessError) => {
406        Log.error('revokeUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
407      })
408  }
409
410  onPageShow(): void {
411    this.refreshStatus();
412  }
413
414  async refreshStatus() {
415    Log.info('Refresh permission status');
416    let isGranted = this.currentGroup === 'LOCATION' ? Constants.PERMISSION_BAN : Constants.PERMISSION_ALLOW;
417    let folderStatus = [false, false, false];
418    let atManager = abilityAccessCtrl.createAtManager();
419    for (let i = 0; i < this.permissions.length; i++) {
420      let permission = this.permissions[i];
421      if (this.currentGroup === 'LOCATION') {
422        continue;
423      }
424      let res = atManager.verifyAccessTokenSync(this.tokenId, permission);
425      if (res != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
426        isGranted = Constants.PERMISSION_BAN;
427      }
428      if (this.currentGroup === 'FOLDER' && res === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
429        switch (permission) {
430          case Permission.READ_WRITE_DOWNLOAD_DIRECTORY:
431            folderStatus[0] = true;
432            break;
433          case Permission.READ_WRITE_DESKTOP_DIRECTORY:
434            folderStatus[1] = true;
435            break;
436          case Permission.READ_WRITE_DOCUMENTS_DIRECTORY:
437            folderStatus[2] = true;
438            break;
439        }
440        results.set(permission, Constants.PERMISSION_DIALOG_SUCCESS);
441      }
442    }
443    this.folderStatus = folderStatus;
444    await this.refreshSelected(isGranted);
445  }
446
447  async refreshSelected(isGranted: number) {
448    this.selected = isGranted;
449    if (this.currentGroup === 'PASTEBOARD') {
450      try {
451        let acManager = abilityAccessCtrl.createAtManager();
452        acManager.getPermissionFlags(this.tokenId, Permission.READ_PASTEBOARD).then(flag => {
453          flag === Constants.PERMISSION_ALLOW_THIS_TIME ? this.selected = Constants.PERMISSION_ONLY_THIS_TIME : null;
454        });
455      } catch (err) {
456        Log.error('getPermissionFlags error: ' + JSON.stringify(err));
457      }
458    } else if (this.currentGroup === 'LOCATION') {
459      try {
460        let acManager = abilityAccessCtrl.createAtManager();
461        let fuzzyState = acManager.verifyAccessTokenSync(this.tokenId, Permission.APPROXIMATELY_LOCATION);
462        fuzzyState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
463          this.selected = Constants.PERMISSION_ALLOWED_ONLY_DURING_USE : null;
464        let accurateStatus = acManager.verifyAccessTokenSync(this.tokenId, Permission.LOCATION);
465        this.accurateIsOn = (accurateStatus == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) ? true : false;
466        let backgroundState = acManager.verifyAccessTokenSync(this.tokenId, Permission.LOCATION_IN_BACKGROUND);
467        backgroundState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
468          this.selected = Constants.PERMISSION_ALLOW : null;
469        acManager.getPermissionFlags(this.tokenId, Permission.APPROXIMATELY_LOCATION).then(flag => {
470          flag === Constants.PERMISSION_ALLOW_THIS_TIME ? this.selected = Constants.PERMISSION_ONLY_THIS_TIME : null;
471        })
472      } catch (err) {
473        Log.error('change location status error: ' + JSON.stringify(err));
474      }
475    } else {
476      await this.checkPermissionFlag();
477    }
478  }
479
480  async checkPermissionFlag() {
481    try {
482      for (const permission of this.permissions) {
483        let acManager = abilityAccessCtrl.createAtManager();
484        let flag = await acManager.getPermissionFlags(this.tokenId, permission);
485        Log.error('permission Flag is ' + flag);
486        if (flag === Constants.PERMISSION_DEFAULT && terminating == false) {
487          PermissionDialogException(Constants.ERR_PERMISSIONS_FLAG_DEFAULT, session);
488          terminating = true;
489          this.context.terminateSelf();
490          return;
491        }
492      }
493    } catch (err) {
494      Log.error('getPermissionFlags error: ' + JSON.stringify(err));
495    }
496  }
497
498  getCheckboxInfo(permission: Permissions): CheckboxInfo {
499    switch (permission) {
500      case Permission.READ_WRITE_DOWNLOAD_DIRECTORY:
501        return new CheckboxInfo($r('app.string.Download_folder'), 0);
502      case Permission.READ_WRITE_DESKTOP_DIRECTORY:
503        return new CheckboxInfo($r('app.string.Desktop_folder'), 1);
504      case Permission.READ_WRITE_DOCUMENTS_DIRECTORY:
505        return new CheckboxInfo($r('app.string.Document_folder'), 2);
506      default:
507        return new CheckboxInfo($r('app.string.Download_folder'), 0);
508    }
509  }
510
511  getMediaDocList() {
512    Log.info('current group ' + this.currentGroup);
513    Log.info('current permissions ' + this.permissions);
514
515    if (this.currentGroup == 'PASTEBOARD') {
516      this.mediaDocListItem.push(
517        new MediaDocObj($r('app.string.per_use_query'), this.permissions, Constants.PERMISSION_ONLY_THIS_TIME)
518      );
519      this.mediaDocListItem.push(
520        new MediaDocObj($r('app.string.always_allow'), this.permissions, Constants.PERMISSION_ALLOW)
521      );
522    } else if (this.currentGroup == 'LOCATION') {
523      this.selected = GlobalContext.load('locationStatus');
524      this.mediaDocListItem.push(
525        new MediaDocObj($r('app.string.per_inquiry'), this.permissions, Constants.PERMISSION_ONLY_THIS_TIME)
526      );
527      if (this.permissions.includes(Permission.LOCATION_IN_BACKGROUND)) {
528        this.mediaDocListItem.push(
529          new MediaDocObj($r('app.string.always_allow'), this.permissions, Constants.PERMISSION_ALLOW)
530        );
531      }
532      if (this.permissions.includes(Permission.APPROXIMATELY_LOCATION)) {
533        this.mediaDocListItem.push(
534          new MediaDocObj(
535            $r('app.string.allowed_only_during_use'),
536            [Permission.APPROXIMATELY_LOCATION],
537            Constants.PERMISSION_ALLOWED_ONLY_DURING_USE
538          )
539        );
540      } else {
541        this.noForeground = true;
542      }
543    } else {
544      this.mediaDocListItem.push(
545        new MediaDocObj($r('app.string.allow'), this.permissions, Constants.PERMISSION_ALLOW)
546      );
547    }
548    this.mediaDocListItem.push(
549      new MediaDocObj($r('app.string.ban'), this.permissions, Constants.PERMISSION_BAN)
550    );
551  }
552
553  async getReason() {
554    this.label = this.applicationInfo.label;
555    if (showSubPermissionsGroup.indexOf(this.currentGroup) != -1) {
556      this.permissions.forEach((permission, idx) => {
557        if (idx > 0) {
558          this.permissionLabels.push($r('app.string.and'));
559        }
560        let label = getPermissionLabel(permission);
561        this.permissionLabels.push(label);
562      });
563    }
564    let hasReason = false;
565    let info = await
566      bundleManager.getBundleInfo(this.bundleName, bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION)
567    for (const permission of this.permissions) {
568      for (const reqPermissionDetail of info.reqPermissionDetails) {
569        if (reqPermissionDetail.name != permission) {
570          continue;
571        }
572        Log.info('reqPermissionDetail: ' + JSON.stringify(reqPermissionDetail));
573        let context = this.context.createModuleContext(this.bundleName, reqPermissionDetail.moduleName);
574        let reason = await context.resourceManager.getStringValue(reqPermissionDetail.reasonId);
575        if (reason !== undefined && !hasReason) {
576          this.reason = reason.slice(Constants.START_SUBSCRIPT, Constants.END_SUBSCRIPT);
577          hasReason = true;
578        }
579      }
580    }
581  }
582
583  aboutToAppear() {
584    this.refreshStatus();
585    this.getMediaDocList();
586    this.getReason();
587    this.setState();
588  }
589
590  setState() {
591    this.hidden = false;
592    this.selected = this.status;
593    bundleManager.getBundleInfo(this.bundleName, bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
594    .then(async res => {
595        this.api = res.targetVersion;
596        this.version = res.versionName;
597        accessTokenId = res.appInfo.accessTokenId;
598        let acManager = abilityAccessCtrl.createAtManager();
599        let accurateStatus = acManager.verifyAccessTokenSync(res.appInfo.accessTokenId, Permission.LOCATION);
600        this.accurateIsOn = (accurateStatus == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) ? true : false;
601        try {
602          let getFlagPermission =
603            this.currentGroup === 'LOCATION' ? Permission.APPROXIMATELY_LOCATION : this.permissions[0];
604          let flag = await acManager.getPermissionFlags(res.appInfo.accessTokenId, getFlagPermission);
605          Log.info(`getPermissionFlags success, data->${JSON.stringify(flag)}`);
606          this.isRisk = (flag == Constants.PERMISSION_POLICY_FIXED) ? true : false;
607          if (flag === Constants.PERMISSION_ALLOW_THIS_TIME) {
608            this.selected = Constants.PERMISSION_ONLY_THIS_TIME;
609          }
610        } catch (err) {
611          Log.error('acManager.getPermissionFlags failed. Cause: ' + JSON.stringify(err));
612        }
613      }).catch((error: BusinessError) => {
614      Log.error('bundle.getBundleInfo failed. Cause: ' + JSON.stringify(error));
615    });
616  }
617
618  async grantFolderPermission(permission: Permissions) {
619    if (this.folderStatus[this.getCheckboxInfo(permission).index]) {
620      this.revokeUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG);
621      this.folderStatus[this.getCheckboxInfo(permission).index] = false;
622      results.set(permission, Constants.ERR_PERMISSION_GRANT_EXCEPTION);
623    } else {
624      await this.grantUserGrantedPermission(accessTokenId, permission);
625      this.folderStatus[this.getCheckboxInfo(permission).index] = true;
626    }
627    // check if every permission has been granted
628    let allGranted = true;
629    for (const permission of this.permissions) {
630      if (!results.has(permission)) {
631        Log.info('permission ' + permission + ' not granted, continue');
632        return;
633      }
634      if (results.get(permission) !== Constants.PERMISSION_DIALOG_SUCCESS) {
635        allGranted = false;
636      }
637    }
638    // if all granted , return status
639    if (allGranted) {
640      ReportDialogResult(this.permissions);
641    }
642  }
643
644  async grantOtherPermissions(item: MediaDocObj) {
645    this.selected = item.index;
646    for (const permission of item.permissions) {
647      Log.info('item click index:' + item.index);
648      if (item.index === Constants.PERMISSION_ALLOW) {
649        if (permission !== Permission.LOCATION) {
650          await this.grantUserGrantedPermission(accessTokenId, permission);
651        }
652      } else if (item.index === Constants.PERMISSION_BAN) {
653        if (permission == Permission.LOCATION && this.accurateIsOn) {
654          this.revokeUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG);
655          this.accurateIsOn = false;
656        } else {
657          this.revokeUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG);
658        }
659      } else if (item.index === Constants.PERMISSION_ONLY_THIS_TIME) {
660        if (permission !== Permission.LOCATION) {
661          await this.revokeUserGrantedPermission(
662            accessTokenId, permission, Constants.PERMISSION_ALLOW_THIS_TIME
663          );
664        }
665      } else if (item.index === Constants.PERMISSION_ALLOWED_ONLY_DURING_USE) {
666        await this.grantUserGrantedPermission(accessTokenId, permission);
667        await this.revokeUserGrantedPermission(
668          accessTokenId, Permission.LOCATION_IN_BACKGROUND, Constants.PERMISSION_FLAG
669        );
670      }
671    }
672    ReportDialogResult(this.permissions);
673    return true;
674  }
675
676  build() {
677    Column() {
678      Row() {
679        Column() {
680          Row() {
681            Text(this.backTitle)
682              .align(Alignment.Start)
683              .fontColor($r('sys.color.font_primary'))
684              .maxLines(Constants.MAXIMUM_HEADER_LINES)
685              .textOverflow({ overflow: TextOverflow.Ellipsis })
686              .fontSize(Constants.TEXT_BIG_FONT_SIZE)
687              .flexGrow(Constants.FLEX_GROW)
688              .fontWeight(FontWeight.Bold)
689              .padding({ left: Constants.PADDING_24, top: Constants.PADDING_20, bottom: Constants.PADDING_20 })
690              .width('80%')
691          }.width(Constants.FULL_WIDTH)
692        }
693        .alignItems(HorizontalAlign.Start)
694        .width(Constants.FULL_WIDTH)
695      }
696      Row() {
697        Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
698          Image(this.applicationInfo.icon)
699            .width(Constants.TERTIARY_IMAGE_WIDTH)
700            .height(Constants.TERTIARY_IMAGE_HEIGHT)
701            .margin({ left: Constants.TERTIARY_IMAGE_MARGIN_LEFT, right: Constants.TERTIARY_IMAGE_MARGIN_RIGHT })
702          Column() {
703            Row() {
704              Text(this.label)
705                .maxLines(Constants.MAXIMUM_HEADER_LINES)
706                .textOverflow({ overflow: TextOverflow.Ellipsis })
707                .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
708                .fontColor($r('sys.color.font_primary'))
709                .fontWeight(FontWeight.Bold)
710                .textAlign(TextAlign.Start)
711            }
712            .width(Constants.TERTIARY_HALF_WIDTH)
713            .margin({ bottom: Constants.TERTIARY_LABEL_MARGIN_BOTTOM })
714
715            Row() {
716              Text($r('app.string.version'))
717                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
718                .fontColor($r('sys.color.font_secondary'))
719                .textAlign(TextAlign.Start)
720              Text(this.version)
721                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
722                .fontColor($r('sys.color.font_secondary'))
723                .textAlign(TextAlign.Start)
724            }
725            .width(Constants.TERTIARY_HALF_WIDTH)
726          }
727        }.margin({ left: Constants.TERTIARY_MARGIN_LEFT })
728      }
729      if (this.isRisk) {
730        Row() {
731          Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
732            Row() {
733              Image($r('app.media.ic_public_fail'))
734                .fillColor($r('sys.color.icon_secondary'))
735                .width(Constants.TERTIARY_RADIO_IMAGE_WIDTH)
736                .height(Constants.TERTIARY_RADIO_IMAGE_HEIGHT)
737                .margin({ right: Constants.TERTIARY_IMAGE_MARGIN_RIGHT })
738              Text($r('app.string.risk_warning'))
739                .fontColor($r('sys.color.font_primary'))
740                .fontSize($r('sys.float.ohos_id_text_size_body1'))
741                .fontWeight(FontWeight.Regular)
742            }.margin({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
743          }
744        }.backgroundColor($r('sys.color.interactive_click'))
745        .borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
746        .padding({ top: Constants.DEFAULT_PADDING_TOP, bottom: Constants.DEFAULT_PADDING_BOTTOM })
747        .margin({ left: Constants.DEFAULT_MARGIN_START, right: Constants.DEFAULT_MARGIN_END })
748      }
749      Row() {
750        Text() {
751          Span(this.backTitle)
752          Span($r('app.string.access_permission'))
753        }
754        .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
755        .fontColor($r('sys.color.icon_secondary'))
756        .fontWeight(FontWeight.Medium)
757        .textAlign(TextAlign.Start)
758        .lineHeight(Constants.SUBTITLE_LINE_HEIGHT)
759      }.width(Constants.FULL_WIDTH)
760      .constraintSize({ minHeight: Constants.SUBTITLE_MIN_HEIGHT })
761      .padding({ top: Constants.SUBTITLE_PADDING_TOP, bottom: Constants.SUBTITLE_PADDING_BOTTOM,
762        left: Constants.TERTIARY_TEXT_MARGIN_LEFT, right: Constants.TERTIARY_IMAGE_MARGIN_RIGHT })
763
764      Column() {
765        List() {
766          if (this.currentGroup === 'FOLDER') {
767            ForEach(this.permissions, (permission: Permissions) => {
768              ListItem() {
769                Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
770                  Row() {
771                    Text(this.getCheckboxInfo(permission).label)
772                      .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
773                      .fontColor($r('sys.color.font_primary'))
774                      .fontWeight(FontWeight.Medium)
775                      .flexGrow(Constants.FLEX_GROW)
776                    Checkbox()
777                      .select(this.folderStatus[this.getCheckboxInfo(permission).index])
778                      .hitTestBehavior(HitTestMode.None)
779                  }
780                  .width(Constants.FULL_WIDTH)
781                  .height(Constants.LISTITEM_ROW_HEIGHT)
782                  .onClick(async () => {
783                      await this.grantFolderPermission(permission)
784                  })
785                }
786              }
787              .padding({
788                left: $r('sys.float.ohos_id_card_margin_start'),
789                right: $r('sys.float.ohos_id_card_margin_end')
790              })
791              .borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
792              .margin({ top: Constants.TERTIARY_LISTITEM_MARGIN_TOP })
793              .linearGradient((this.isCheck === permission) ? {
794                angle: 90,
795                direction: GradientDirection.Right,
796                colors: [['#DCEAF9', 0.0], ['#FAFAFA', 1.0]]
797              } : {
798                angle: 90,
799                direction: GradientDirection.Right,
800                colors: []
801              })
802              .onTouch(event => {
803                if (event === undefined) {
804                  return;
805                }
806                if (event.type === TouchType.Down) {
807                  this.isCheck = permission;
808                }
809                if (event.type === TouchType.Up) {
810                  this.isCheck = '';
811                }
812              })
813            }, (permission: Permissions) => JSON.stringify(permission))
814          } else {
815            ForEach(this.mediaDocListItem, (item: MediaDocObj) => {
816              ListItem() {
817                Column() {
818                  Row() {
819                    Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
820                      Row() {
821                        Text(item.name)
822                          .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
823                          .fontColor($r('sys.color.font_primary'))
824                          .fontWeight(FontWeight.Medium)
825                          .flexGrow(Constants.FLEX_GROW)
826                        Radio({ value: 'Radio', group: 'radioGroup' })
827                          .checked(item.index === this.selected)
828                          .hitTestBehavior(HitTestMode.None)
829                          .height(Constants.SHAPE_DIA)
830                          .width(Constants.SHAPE_DIA)
831                      }
832                      .width(Constants.FULL_WIDTH)
833                      .height(Constants.LISTITEM_ROW_HEIGHT)
834                      .onClick(async () => {
835                        await this.grantOtherPermissions(item);
836                      })
837                    }
838                  }
839                }
840              }
841              .padding({
842                left: $r('sys.float.ohos_id_card_margin_start'),
843                right: $r('sys.float.ohos_id_card_margin_end')
844              })
845              .borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
846              .linearGradient((this.isTouch === item.index) ? {
847                angle: 90,
848                direction: GradientDirection.Right,
849                colors: [['#DCEAF9', 0.0], ['#FAFAFA', 1.0]]
850              } : {
851                angle: 90,
852                direction: GradientDirection.Right,
853                colors: []
854              })
855              .onTouch(event => {
856                if (event === undefined) {
857                  return;
858                }
859                if (event.type === TouchType.Down) {
860                  this.isTouch = item.index;
861                }
862                if (event.type === TouchType.Up) {
863                  this.isTouch = -1;
864                }
865              })
866              .margin({ top: Constants.TERTIARY_LISTITEM_MARGIN_TOP })
867            }, (item: MediaDocObj) => JSON.stringify(item))
868          }
869        }
870        .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
871        .backgroundColor($r('sys.color.comp_background_list_card'))
872        .padding(Constants.LIST_PADDING_TOP)
873        .divider({
874          strokeWidth: Constants.DIVIDER,
875          color: $r('sys.color.comp_divider'),
876          startMargin: Constants.DEFAULT_MARGIN_START,
877          endMargin: Constants.DEFAULT_MARGIN_END
878        })
879
880        if (this.permissions.includes(Permission.LOCATION)) {
881          Column() {
882            Row() {
883              Text($r('app.string.precise_location'))
884                .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
885                .fontColor($r('sys.color.font_primary'))
886                .fontWeight(FontWeight.Medium)
887                .flexGrow(Constants.FLEX_GROW)
888              Toggle({ type: ToggleType.Switch, isOn: this.accurateIsOn })
889                .selectedColor($r('sys.color.icon_emphasize'))
890                .switchPointColor($r('sys.color.comp_background_primary_contrary'))
891                .onChange((isOn: boolean) => {
892                  let acManager = abilityAccessCtrl.createAtManager()
893                  if (isOn) {
894                    acManager.grantUserGrantedPermission(accessTokenId, Permission.LOCATION, Constants.PERMISSION_FLAG)
895                    .then(() => {
896                      this.accurateIsOn = true
897                    })
898                  } else {
899                    acManager.revokeUserGrantedPermission(accessTokenId, Permission.LOCATION, Constants.PERMISSION_FLAG)
900                    .then(() => {
901                      this.accurateIsOn = false
902                    })
903                  }
904                })
905                .padding({ right: 0 })
906                .enabled(this.selected !== Constants.PERMISSION_BAN)
907            }.width(Constants.FULL_WIDTH)
908            .height(Constants.LISTITEM_ROW_HEIGHT)
909          }.margin({ top: Constants.LOCATION_MARGIN_TOP, bottom: Constants.LOCATION_MARGIN_BOTTOM })
910          .padding({
911            left: Constants.DEFAULT_PADDING_START,
912            right: Constants.DEFAULT_PADDING_END,
913            top: Constants.TERTIARY_LIST_PADDING_TOP,
914            bottom: Constants.TERTIARY_LIST_PADDING_BOTTOM
915          })
916          .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
917          .backgroundColor($r('sys.color.comp_background_list_card'))
918
919          Row() {
920            Text($r('app.string.get_the_exact_position'))
921              .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
922              .fontColor($r('sys.color.font_secondary'))
923              .lineHeight(Constants.TEXT_SMALL_LINE_HEIGHT)
924          }.width(Constants.FULL_WIDTH)
925          .padding({
926            left: Constants.DEFAULT_PADDING_START,
927            right: Constants.DEFAULT_PADDING_END,
928          })
929        }
930      }
931      .padding({
932        left: Constants.LIST_PADDING_LEFT,
933        right: Constants.LIST_PADDING_LEFT
934      })
935      .width(Constants.FULL_WIDTH)
936      .enabled(!this.isRisk && !this.noForeground)
937      .opacity((!this.isRisk && !this.noForeground) ? 1 : $r('sys.float.ohos_id_alpha_disabled'))
938    }
939    .visibility(this.hidden ? Visibility.None : Visibility.Visible)
940    .width(Constants.FULL_WIDTH)
941  }
942}
943