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 router from '@ohos.router';
18import common from '@ohos.app.ability.common';
19import bundleManager from '@ohos.bundle.bundleManager';
20import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
21import { BusinessError } from '@ohos.base';
22import { showSubPermissionsGroup } from '../common/model/permissionGroup';
23import { Log, getPermissionLabel } from '../common/utils/utils';
24import Constants from '../common/utils/constant';
25import { MediaDocObj, RouterParams3, AppInfo, CheckboxInfo } from '../common/model/typedef';
26import { GlobalContext } from '../common/utils/globalContext';
27
28const FUZZY_LOCATION_PERMISSION = 'ohos.permission.APPROXIMATELY_LOCATION';
29const PRECISE_LOCATION_PERMISSION = 'ohos.permission.LOCATION';
30const BACKGROUND_LOCATION_PERMISSION = 'ohos.permission.LOCATION_IN_BACKGROUND';
31const DOWNLOAD_PERMISSION = 'ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY';
32const DESKTOP_PERMISSION = 'ohos.permission.READ_WRITE_DESKTOP_DIRECTORY';
33const DOCUMENTS_PERMISSION = 'ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY';
34const PASTE = 'ohos.permission.READ_PASTEBOARD';
35const showPrecise: number[] = [Constants.PERMISSION_ALLOW, Constants.PERMISSION_ALLOWED_ONLY_DURING_USE];
36let accessTokenId: number = 0;
37let reqPermissionInfo: bundleManager.ReqPermissionDetail;
38
39@Entry
40@Component
41struct mediaDocumentPage {
42  private backTitle: ResourceStr = (router.getParams() as RouterParams3).backTitle;
43  private permissions: Permissions[] = (router.getParams() as RouterParams3).permission;
44  private tokenId: number = (router.getParams() as RouterParams3).tokenId;
45  @State currentGroup: string = GlobalContext.load('currentPermissionGroup');
46  @State folderStatus: boolean[] = GlobalContext.load('folderStatus');
47  @State refresh: boolean = false;
48  @State selected: number = 0; // Permission status array
49  @State accurateIsOn: boolean = true;
50  @State isRefreshReason: number = 0
51
52  build() {
53    Column() {
54      GridRow({ gutter: Constants.GUTTER, columns: {
55        xs: Constants.XS_COLUMNS, sm: Constants.SM_COLUMNS, md: Constants.MD_COLUMNS, lg: Constants.LG_COLUMNS } }) {
56        GridCol({
57          span: { xs: Constants.XS_SPAN, sm: Constants.SM_SPAN, md: Constants.MD_SPAN, lg: Constants.LG_SPAN },
58          offset: { xs: Constants.XS_OFFSET, sm: Constants.SM_OFFSET, md: Constants.MD_OFFSET, lg: Constants.LG_OFFSET }
59        }) {
60          Row() {
61            Column() {
62              Row() {
63                backBar({ title: JSON.stringify(this.backTitle), recordable: false })
64              }
65              Row() {
66                Column() {
67                  mediaDocumentItem({
68                    selected: $selected,
69                    accurateIsOn: $accurateIsOn,
70                    isRefreshReason: $isRefreshReason,
71                    folderStatus: $folderStatus
72                  })
73                }.width(Constants.FULL_WIDTH)
74              }
75              .margin({ top: Constants.TITLE_MARGIN_BOTTOM })
76              .layoutWeight(Constants.LAYOUT_WEIGHT)
77            }
78          }
79          .height(Constants.FULL_HEIGHT)
80          .width(Constants.FULL_WIDTH)
81          .backgroundColor($r('sys.color.background_secondary'))
82        }
83      }.backgroundColor($r('sys.color.background_secondary'))
84    }
85  }
86
87  onPageShow() {
88    if (this.refresh) {
89      this.refreshStatus();
90    }
91    this.refresh = true;
92  }
93
94  refreshStatus() {
95    if (reqPermissionInfo) {
96      this.isRefreshReason ++;
97    }
98    Log.info('Refresh permission status');
99    let isGranted = this.currentGroup === 'LOCATION' ? Constants.PERMISSION_BAN : Constants.PERMISSION_ALLOW;
100    let folderStatus = [false, false, false];
101    let atManager = abilityAccessCtrl.createAtManager();
102    for (let i = 0; i < this.permissions.length; i++) {
103      let permission = this.permissions[i];
104      if (this.currentGroup === 'LOCATION') {
105        continue;
106      }
107      let res = atManager.verifyAccessTokenSync(this.tokenId, permission);
108      if (res != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
109        isGranted = Constants.PERMISSION_BAN;
110      }
111      if (this.currentGroup === 'FOLDER' && res === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
112        switch (permission) {
113          case DOWNLOAD_PERMISSION:
114            folderStatus[0] = true;
115            break;
116          case DESKTOP_PERMISSION:
117            folderStatus[1] = true;
118            break;
119          case DOCUMENTS_PERMISSION:
120            folderStatus[2] = true;
121            break;
122        }
123      }
124    }
125    Log.info('isGranted: ' + JSON.stringify(isGranted));
126    this.folderStatus = folderStatus;
127
128    this.refreshSelected(isGranted);
129  }
130
131  refreshSelected(isGranted: number) {
132    this.selected = isGranted;
133    if (this.currentGroup === 'PASTEBOARD') {
134      try {
135        let acManager = abilityAccessCtrl.createAtManager();
136        acManager.getPermissionFlags(this.tokenId, PASTE).then(flag => {
137          flag === Constants.PERMISSION_ALLOW_THIS_TIME ? this.selected = Constants.PERMISSION_ONLY_THIS_TIME : null;
138        })
139      } catch (err) {
140        Log.error('getPermissionFlags error: ' + JSON.stringify(err));
141      }
142    }
143    if (this.currentGroup === 'LOCATION') {
144      try {
145        let acManager = abilityAccessCtrl.createAtManager();
146        let fuzzyState = acManager.verifyAccessTokenSync(this.tokenId, FUZZY_LOCATION_PERMISSION);
147        fuzzyState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
148          this.selected = Constants.PERMISSION_ALLOWED_ONLY_DURING_USE : null;
149        let accurateStatus = acManager.verifyAccessTokenSync(this.tokenId, PRECISE_LOCATION_PERMISSION);
150        this.accurateIsOn = (accurateStatus == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) ? true : false;
151        let backgroundState = acManager.verifyAccessTokenSync(this.tokenId, BACKGROUND_LOCATION_PERMISSION);
152        backgroundState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
153          this.selected = Constants.PERMISSION_ALLOW : null;
154        acManager.getPermissionFlags(this.tokenId, FUZZY_LOCATION_PERMISSION ).then(flag => {
155          flag === Constants.PERMISSION_ALLOW_THIS_TIME ? this.selected = Constants.PERMISSION_ONLY_THIS_TIME : null;
156        })
157      } catch (err) {
158        Log.error('change location status error: ' + JSON.stringify(err));
159      }
160    }
161  }
162}
163
164@Component
165struct mediaDocumentItem {
166  private context = getContext(this) as common.UIAbilityContext;
167  private backTitle: ResourceStr = (router.getParams() as RouterParams3).backTitle;
168  private bundleName: string = (router.getParams() as RouterParams3).bundleName;
169  private permissions: Permissions[] = (router.getParams() as RouterParams3).permission;
170  private status: number = (router.getParams() as RouterParams3).status;
171  @State currentGroup: string = GlobalContext.load('currentPermissionGroup');
172  @State applicationInfo: AppInfo = GlobalContext.load('applicationInfo');
173  @Link folderStatus: boolean[];
174  @State mediaDocListItem: MediaDocObj[] = []; // Permission information array
175  @Link selected: number;
176  @Link accurateIsOn: boolean;
177  @State isRisk: boolean = false; // Whether it is a risky application
178  @State noForeground: boolean = false;
179  @State isTouch: number = -1;
180  @State isCheck: string = '';
181  @State reason: string = '';
182  @State label: string = '';
183  @State version: string = '';
184  @State permissionLabels: Array<ResourceStr> = [];
185  @Link @Watch('updateReason') isRefreshReason: number;
186
187  /**
188   * Grant permissions to the app
189   * @param {Number} accessTokenId
190   * @param {String} permission permission name
191   */
192  grantUserGrantedPermission(accessTokenId: number, permission: Permissions) {
193    abilityAccessCtrl.createAtManager().grantUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG)
194      .then(() => {})
195      .catch((error: BusinessError) => {
196        Log.error('grantUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
197      })
198  }
199
200  /**
201   * Deauthorize the app
202   * @param {Number} accessTokenId
203   * @param {String} permission permission name
204   */
205  revokeUserGrantedPermission(accessTokenId: number, permission: Permissions, flag: number) {
206    abilityAccessCtrl.createAtManager().revokeUserGrantedPermission(accessTokenId, permission, flag)
207      .then(() => {})
208      .catch((error: BusinessError) => {
209        Log.error('revokeUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
210      })
211  }
212
213  /**
214   * Update reason
215   */
216  updateReason() {
217    bundleManager.getApplicationInfo(
218      this.applicationInfo.bundleName, bundleManager.ApplicationFlag.GET_APPLICATION_INFO_DEFAULT
219    ).then(appInfo => {
220      let bundleContext = this.context.createBundleContext(this.bundleName)
221      bundleContext.resourceManager.getStringValue(appInfo.labelId, (error, value) => {
222        if (value) {
223          this.applicationInfo.label = value;
224          GlobalContext.store('applicationInfo', this.applicationInfo);
225          this.label = value
226        }
227      })
228    }).catch((error: BusinessError) => {
229      Log.error('getApplicationInfo error: ' + JSON.stringify(error));
230    })
231    let context = this.context.createModuleContext(this.bundleName, reqPermissionInfo.moduleName);
232    context.resourceManager.getStringValue(reqPermissionInfo.reasonId).then(value => {
233      if (value !== undefined) {
234        this.reason = value.slice(Constants.START_SUBSCRIPT, Constants.END_SUBSCRIPT);
235      }
236    })
237  }
238
239  getCheckboxInfo(permission: Permissions): CheckboxInfo {
240    switch (permission) {
241      case DOWNLOAD_PERMISSION:
242        return new CheckboxInfo($r('app.string.Download_folder'), 0);
243      case DESKTOP_PERMISSION:
244        return new CheckboxInfo($r('app.string.Desktop_folder'), 1);
245      case DOCUMENTS_PERMISSION:
246        return new CheckboxInfo($r('app.string.Document_folder'), 2);
247      default:
248        return new CheckboxInfo($r('app.string.Download_folder'), 0);
249    }
250  }
251
252  getMediaDocList() {
253    if (this.currentGroup == 'PASTEBOARD') {
254      this.mediaDocListItem.push(
255        new MediaDocObj($r('app.string.per_use_query'), this.permissions, Constants.PERMISSION_ONLY_THIS_TIME)
256      );
257      this.mediaDocListItem.push(
258        new MediaDocObj($r('app.string.always_allow'), this.permissions, Constants.PERMISSION_ALLOW)
259      );
260    } else if (this.currentGroup == 'LOCATION') {
261      this.selected = GlobalContext.load('locationStatus');
262      this.mediaDocListItem.push(
263        new MediaDocObj($r('app.string.per_inquiry'), this.permissions, Constants.PERMISSION_ONLY_THIS_TIME)
264      );
265      if (this.permissions.includes(BACKGROUND_LOCATION_PERMISSION)) {
266        this.mediaDocListItem.push(
267          new MediaDocObj($r('app.string.always_allow'), this.permissions, Constants.PERMISSION_ALLOW)
268        );
269      }
270      if (this.permissions.includes(FUZZY_LOCATION_PERMISSION)) {
271        this.mediaDocListItem.push(
272          new MediaDocObj(
273            $r('app.string.allowed_only_during_use'),
274            [FUZZY_LOCATION_PERMISSION],
275            Constants.PERMISSION_ALLOWED_ONLY_DURING_USE
276          )
277        );
278      } else {
279        this.noForeground = true;
280      }
281    } else {
282      this.mediaDocListItem.push(
283        new MediaDocObj($r('app.string.allow'), this.permissions, Constants.PERMISSION_ALLOW)
284      );
285    }
286    this.mediaDocListItem.push(
287      new MediaDocObj($r('app.string.ban'), this.permissions, Constants.PERMISSION_BAN)
288    );
289  }
290
291  getReason() {
292    this.label = this.applicationInfo.label;
293    if (showSubPermissionsGroup.indexOf(this.currentGroup) != -1) {
294      this.permissions.forEach((permission, idx) => {
295        if (idx > 0) {
296          this.permissionLabels.push($r('app.string.and'))
297        }
298        let label = getPermissionLabel(permission)
299        this.permissionLabels.push(label);
300      })
301    }
302    let hasReason = false;
303    bundleManager.getBundleInfo(this.bundleName, bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION)
304      .then(info => {
305        this.permissions.forEach(permission => {
306          info.reqPermissionDetails.forEach(reqPermissionDetail => {
307            if (reqPermissionDetail.name == permission) {
308              Log.info('reqPermissionDetail: ' + JSON.stringify(reqPermissionDetail));
309              let context = this.context.createModuleContext(this.bundleName, reqPermissionDetail.moduleName);
310              context.resourceManager.getStringValue(reqPermissionDetail.reasonId).then(value => {
311                if (value !== undefined && !hasReason) {
312                  this.reason = value.slice(Constants.START_SUBSCRIPT, Constants.END_SUBSCRIPT);
313                  reqPermissionInfo = reqPermissionDetail;
314                  hasReason = true;
315                }
316              })
317            }
318          })
319        })
320      })
321  }
322
323  /**
324   * Lifecycle function, executed when the page is initialized
325   */
326  aboutToAppear() {
327    this.selected = this.status;
328    this.getMediaDocList();
329    this.getReason();
330
331    bundleManager.getBundleInfo(this.bundleName, bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
332    .then(res => {
333      this.version = res.versionName;
334      accessTokenId = res.appInfo.accessTokenId;
335      let acManager = abilityAccessCtrl.createAtManager();
336      let accurateStatus = acManager.verifyAccessTokenSync(res.appInfo.accessTokenId, PRECISE_LOCATION_PERMISSION);
337      this.accurateIsOn = (accurateStatus == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) ? true : false;
338      try {
339        let getFlagPermission = this.currentGroup === 'LOCATION' ? FUZZY_LOCATION_PERMISSION : this.permissions[0];
340        acManager.getPermissionFlags(res.appInfo.accessTokenId, getFlagPermission).then((flag) => {
341          Log.info(`getPermissionFlags success, data->${JSON.stringify(flag)}`);
342          this.isRisk = (flag == Constants.PERMISSION_POLICY_FIXED) ? true : false;
343          if (flag === Constants.PERMISSION_ALLOW_THIS_TIME) {
344            this.selected = Constants.PERMISSION_ONLY_THIS_TIME;
345          }
346        })
347      } catch (err) {
348        Log.error('acManager.getPermissionFlags failed. Cause: ' + JSON.stringify(err));
349      }
350    }).catch((error: BusinessError) => {
351      Log.error('bundle.getBundleInfo failed. Cause: ' + JSON.stringify(error));
352    })
353  }
354
355  build() {
356    Column() {
357      Row() {
358        Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
359          Image(this.applicationInfo.icon)
360            .width(Constants.TERTIARY_IMAGE_WIDTH)
361            .height(Constants.TERTIARY_IMAGE_HEIGHT)
362            .margin({ left: Constants.TERTIARY_IMAGE_MARGIN_LEFT, right: Constants.TERTIARY_IMAGE_MARGIN_RIGHT })
363          Column() {
364            Row() {
365              Text(this.label)
366                .maxLines(Constants.MAXIMUM_HEADER_LINES)
367                .textOverflow({ overflow: TextOverflow.Ellipsis })
368                .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
369                .fontColor($r('sys.color.font_primary'))
370                .fontWeight(FontWeight.Bold)
371                .textAlign(TextAlign.Start)
372            }
373            .width(Constants.TERTIARY_HALF_WIDTH)
374            .margin({ bottom: Constants.TERTIARY_LABEL_MARGIN_BOTTOM })
375            Row() {
376              Text($r('app.string.version'))
377                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
378                .fontColor($r('sys.color.font_secondary'))
379                .textAlign(TextAlign.Start)
380              Text(this.version)
381                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
382                .fontColor($r('sys.color.font_secondary'))
383                .textAlign(TextAlign.Start)
384            }
385            .width(Constants.TERTIARY_HALF_WIDTH)
386          }
387        }.margin({ left: Constants.TERTIARY_MARGIN_LEFT })
388      }
389      if (this.reason || this.permissionLabels.length > 0) {
390        Row() {
391          Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
392            Row() {
393              Text() {
394                if (this.permissionLabels.length > 0) {
395                  ForEach(this.permissionLabels, (item: ResourceStr) => {
396                    Span(item)
397                  })
398                  Span(this.reason ? $r('app.string.comma') : $r('app.string.period'))
399                }
400                Span(this.reason)
401              }
402                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
403                .fontColor($r('sys.color.icon_secondary'))
404                .textAlign(TextAlign.Start)
405            }.margin({ left: Constants.TERTIARY_IMAGE_MARGIN_LEFT, right: Constants.TERTIARY_IMAGE_MARGIN_RIGHT })
406          }
407        }
408        .margin({
409          top: Constants.TERTIARY_ROW_MARGIN_TOP,
410          left: Constants.DEFAULT_MARGIN_START,
411          bottom: Constants.DEFAULT_MARGIN_BOTTOM
412        })
413      }
414      if (this.isRisk) {
415        Row() {
416          Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
417            Row() {
418              Image($r('app.media.ic_public_fail'))
419                .fillColor($r('sys.color.icon_secondary'))
420                .width(Constants.TERTIARY_RADIO_IMAGE_WIDTH)
421                .height(Constants.TERTIARY_RADIO_IMAGE_HEIGHT)
422                .margin({ right: Constants.TERTIARY_IMAGE_MARGIN_RIGHT })
423              Text($r('app.string.risk_warning'))
424                .fontColor($r('sys.color.font_primary'))
425                .fontSize($r('sys.float.ohos_id_text_size_body1'))
426                .fontWeight(FontWeight.Regular)
427            }.margin({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
428          }
429        }.backgroundColor($r('sys.color.interactive_click'))
430        .borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
431        .padding({ top: Constants.DEFAULT_PADDING_TOP, bottom: Constants.DEFAULT_PADDING_BOTTOM })
432        .margin({ left: Constants.DEFAULT_MARGIN_START, right: Constants.DEFAULT_MARGIN_END })
433      }
434      Row() {
435        Text() {
436          Span(this.backTitle)
437          Span($r('app.string.access_permission'))
438        }
439          .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
440          .fontColor($r('sys.color.icon_secondary'))
441          .fontWeight(FontWeight.Medium)
442          .textAlign(TextAlign.Start)
443          .lineHeight(Constants.SUBTITLE_LINE_HEIGHT)
444      }.width(Constants.FULL_WIDTH)
445      .constraintSize({ minHeight: Constants.SUBTITLE_MIN_HEIGHT })
446      .padding({ top: Constants.SUBTITLE_PADDING_TOP, bottom: Constants.SUBTITLE_PADDING_BOTTOM,
447        left: Constants.TERTIARY_TEXT_MARGIN_LEFT, right: Constants.TERTIARY_IMAGE_MARGIN_RIGHT})
448      Column() {
449        List() {
450          if (this.currentGroup === 'FOLDER') {
451            ForEach(this.permissions, (permission: Permissions) => {
452              ListItem() {
453                Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
454                  Row() {
455                    Text(this.getCheckboxInfo(permission).label)
456                      .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
457                      .fontColor($r('sys.color.font_primary'))
458                      .fontWeight(FontWeight.Medium)
459                      .flexGrow(Constants.FLEX_GROW)
460                    Checkbox()
461                      .select(this.folderStatus[this.getCheckboxInfo(permission).index])
462                      .hitTestBehavior(HitTestMode.None)
463                  }
464                  .width(Constants.FULL_WIDTH)
465                  .height(Constants.LISTITEM_ROW_HEIGHT)
466                  .onClick(() => {
467                    if (this.folderStatus[this.getCheckboxInfo(permission).index]) {
468                      this.revokeUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG);
469                      this.folderStatus[this.getCheckboxInfo(permission).index] = false;
470                    } else {
471                      this.grantUserGrantedPermission(accessTokenId, permission);
472                      this.folderStatus[this.getCheckboxInfo(permission).index] = true;
473                    }
474                  })
475                }
476              }
477              .padding({
478                left: $r('sys.float.ohos_id_card_margin_start'),
479                right: $r('sys.float.ohos_id_card_margin_end')
480              })
481              .borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
482              .margin({ top: Constants.TERTIARY_LISTITEM_MARGIN_TOP })
483              .linearGradient((this.isCheck === permission) ? {
484                angle: 90,
485                direction: GradientDirection.Right,
486                colors: [['#DCEAF9', 0.0], ['#FAFAFA', 1.0]]
487              } : {
488                angle: 90,
489                direction: GradientDirection.Right,
490                colors: []
491              })
492              .onTouch(event => {
493                if (event === undefined) {
494                  return;
495                }
496                if (event.type === TouchType.Down) {
497                  this.isCheck = permission;
498                }
499                if (event.type === TouchType.Up) {
500                  this.isCheck = '';
501                }
502              })
503            }, (permission: Permissions) => JSON.stringify(permission))
504          } else {
505            ForEach(this.mediaDocListItem, (item: MediaDocObj) => {
506              ListItem() {
507                Column() {
508                  Row() {
509                    Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
510                      Row() {
511                        Text(item.name)
512                          .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
513                          .fontColor($r('sys.color.font_primary'))
514                          .fontWeight(FontWeight.Medium)
515                          .flexGrow(Constants.FLEX_GROW)
516                        Radio({ value: 'Radio', group: 'radioGroup' })
517                          .checked(item.index === this.selected)
518                          .hitTestBehavior(HitTestMode.None)
519                          .height(Constants.SHAPE_DIA)
520                          .width(Constants.SHAPE_DIA)
521                      }
522                      .width(Constants.FULL_WIDTH)
523                      .height(Constants.LISTITEM_ROW_HEIGHT)
524                      .onClick(() => {
525                        this.selected = item.index;
526                        item.permissions.forEach((permission): boolean => {
527                          if (item.index === Constants.PERMISSION_ALLOW) {
528                            if (permission === PRECISE_LOCATION_PERMISSION) {
529                              return false;
530                            }
531                            this.grantUserGrantedPermission(accessTokenId, permission);
532                          } else if (item.index === Constants.PERMISSION_BAN) {
533                            if (permission == PRECISE_LOCATION_PERMISSION && this.accurateIsOn) {
534                              this.revokeUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG);
535                              this.accurateIsOn = false;
536                            } else {
537                              this.revokeUserGrantedPermission(accessTokenId, permission, Constants.PERMISSION_FLAG);
538                            }
539                          } else if (item.index === Constants.PERMISSION_ONLY_THIS_TIME) {
540                            if (permission === PRECISE_LOCATION_PERMISSION) {
541                              return false;
542                            }
543                            this.revokeUserGrantedPermission(
544                              accessTokenId, permission, Constants.PERMISSION_ALLOW_THIS_TIME
545                            );
546                          } else if (item.index === Constants.PERMISSION_ALLOWED_ONLY_DURING_USE) {
547                            this.grantUserGrantedPermission(accessTokenId, permission);
548                            this.revokeUserGrantedPermission(
549                              accessTokenId, BACKGROUND_LOCATION_PERMISSION, Constants.PERMISSION_FLAG
550                            );
551                          }
552                          return true;
553                        })
554                      })
555                    }
556                  }
557                }
558              }
559              .padding({
560                left: $r('sys.float.ohos_id_card_margin_start'),
561                right: $r('sys.float.ohos_id_card_margin_end')
562              })
563              .borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
564              .linearGradient((this.isTouch === item.index) ? {
565                  angle: 90,
566                  direction: GradientDirection.Right,
567                  colors: [['#DCEAF9', 0.0], ['#FAFAFA', 1.0]]
568                } : {
569                  angle: 90,
570                  direction: GradientDirection.Right,
571                  colors: []
572                })
573              .onTouch(event => {
574                if (event === undefined) {
575                  return;
576                }
577                if (event.type === TouchType.Down) {
578                  this.isTouch = item.index;
579                }
580                if (event.type === TouchType.Up) {
581                  this.isTouch = -1;
582                }
583              })
584              .margin({ top: Constants.TERTIARY_LISTITEM_MARGIN_TOP })
585            }, (item: MediaDocObj) => JSON.stringify(item))
586          }
587        }
588        .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
589        .backgroundColor($r('sys.color.comp_background_list_card'))
590        .padding(Constants.LIST_PADDING_TOP)
591        .divider({
592          strokeWidth: Constants.DIVIDER,
593          color: $r('sys.color.comp_divider'),
594          startMargin: Constants.DEFAULT_MARGIN_START,
595          endMargin: Constants.DEFAULT_MARGIN_END
596        })
597
598        if (this.permissions.includes(PRECISE_LOCATION_PERMISSION) && showPrecise.includes(this.selected)) {
599          Column() {
600            Row() {
601              Text($r('app.string.precise_location'))
602                .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
603                .fontColor($r('sys.color.font_primary'))
604                .fontWeight(FontWeight.Medium)
605                .flexGrow(Constants.FLEX_GROW)
606              Toggle({ type: ToggleType.Switch, isOn: this.accurateIsOn })
607                .selectedColor($r('sys.color.icon_emphasize'))
608                .switchPointColor($r('sys.color.comp_background_primary_contrary'))
609                .onChange((isOn: boolean) => {
610                  let acManager = abilityAccessCtrl.createAtManager()
611                  if (isOn) {
612                    acManager.grantUserGrantedPermission(
613                      accessTokenId, PRECISE_LOCATION_PERMISSION, Constants.PERMISSION_FLAG
614                    ).then(() => { this.accurateIsOn = true })
615                  } else {
616                    acManager.revokeUserGrantedPermission(
617                      accessTokenId, PRECISE_LOCATION_PERMISSION, Constants.PERMISSION_FLAG
618                    ).then(() => { this.accurateIsOn = false })
619                  }
620                })
621                .padding({ right: 0 })
622            }.width(Constants.FULL_WIDTH)
623            .height(Constants.LISTITEM_ROW_HEIGHT)
624          }.margin({ top: Constants.LOCATION_MARGIN_TOP, bottom: Constants.LOCATION_MARGIN_BOTTOM })
625          .padding({
626            left: Constants.DEFAULT_PADDING_START,
627            right: Constants.DEFAULT_PADDING_END,
628            top: Constants.TERTIARY_LIST_PADDING_TOP,
629            bottom: Constants.TERTIARY_LIST_PADDING_BOTTOM
630          })
631          .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
632          .backgroundColor($r('sys.color.comp_background_list_card'))
633
634          Row() {
635            Text($r('app.string.get_the_exact_position'))
636              .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
637              .fontColor($r('sys.color.font_secondary'))
638              .lineHeight(Constants.TEXT_SMALL_LINE_HEIGHT)
639          }.width(Constants.FULL_WIDTH)
640          .padding({
641            left: Constants.DEFAULT_PADDING_START,
642            right: Constants.DEFAULT_PADDING_END,
643          })
644        }
645      }
646      .padding({
647        left: Constants.LIST_PADDING_LEFT,
648        right: Constants.LIST_PADDING_LEFT
649      })
650      .width(Constants.FULL_WIDTH)
651      .height(Constants.FULL_HEIGHT)
652      .enabled(!this.isRisk && !this.noForeground)
653      .opacity((!this.isRisk && !this.noForeground) ? 1 : $r('sys.float.ohos_id_alpha_disabled'))
654    }
655    .width(Constants.FULL_WIDTH)
656  }
657}
658