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