• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { backBar } from '../common/components/backBar';
17import common from '@ohos.app.ability.common';
18import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
19import bundleManager from '@ohos.bundle.bundleManager';
20import { BusinessError } from '@ohos.base';
21import { groups } from '../common/model/permissionGroup';
22import Constants from '../common/utils/constant';
23import { Log, verifyAccessToken, getGroupIdByPermission, supportPermission } from '../common/utils/utils';
24import { PermissionObj, AppInfo } from '../common/model/typedef';
25import { GlobalContext } from '../common/utils/globalContext';
26import { Permission } from '../common/model/definition';
27
28@Entry
29@Component
30struct appNamePlusPage {
31  private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
32  @State allowedListItem: PermissionObj[] = []; // Array of allowed permissions
33  @State bannedListItem: PermissionObj[] = []; // array of forbidden permissions
34  @State applicationInfo: AppInfo = GlobalContext.load('applicationInfo'); // Routing jump data
35  @State bundleName: string = GlobalContext.load('bundleName');
36  @State label: string = '';
37  @State isTouch: string = '';
38  @State isGranted: number = Constants.PERMISSION_ALLOW;
39  @State folderStatus: boolean[] = [false, false, false];
40  @State reqUserPermissions: Permission[] = [];
41
42  @Builder ListItemLayout(item: PermissionObj, status: number) {
43    ListItem() {
44      Row() {
45        Column() {
46          Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
47            Row() {
48              Text(item.groupName)
49                .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
50                .fontColor($r('sys.color.font_primary'))
51                .fontWeight(FontWeight.Medium)
52                .flexGrow(Constants.FLEX_GROW)
53              SymbolGlyph($r('sys.symbol.chevron_forward'))
54                .width(Constants.IMAGE_WIDTH)
55                .height(Constants.IMAGE_HEIGHT)
56                .fontSize(Constants.FONT_SIZE_18_vp)
57                .fontColor([$r('sys.color.icon_tertiary')])
58                .fontWeight(FontWeight.Medium)
59            }
60            .width(Constants.FULL_WIDTH)
61            .height(Constants.LISTITEM_ROW_HEIGHT)
62          }
63        }.onClick(() => {
64          GlobalContext.store('currentPermissionGroup', item.group);
65          this.getUIContext().getRouter().pushUrl({
66            url: 'pages/application-tertiary',
67            params: {
68              bundleName: this.applicationInfo.bundleName,
69              backTitle: item.groupName,
70              permission: item.permission,
71              status,
72              tokenId: this.applicationInfo.tokenId
73            }
74          });
75        })
76      }
77    }.padding({ left: $r('sys.float.ohos_id_card_margin_start'), right: $r('sys.float.ohos_id_card_margin_end') })
78    .borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
79    .linearGradient((this.isTouch === item.group) ? {
80        angle: 90,
81        direction: GradientDirection.Right,
82        colors: [['#DCEAF9', 0.0], ['#FAFAFA', 1.0]]
83      } : {
84        angle: 90,
85        direction: GradientDirection.Right,
86        colors: [[$r('sys.color.comp_background_list_card'), 1], [$r('sys.color.comp_background_list_card'), 1]]
87      })
88    .onTouch(event => {
89      if (event === undefined) {
90        return;
91      }
92      if (event.type === TouchType.Down) {
93        this.isTouch = item.group;
94      }
95      if (event.type === TouchType.Up) {
96        this.isTouch = '';
97      }
98    })
99  }
100
101  async getReqUserPermissions(info: AppInfo) {
102    let acManager = abilityAccessCtrl.createAtManager();
103    if (info.permissions.length > 0) {
104      for (let j = 0; j < info.permissions.length; j++) {
105        let permission = info.permissions[j] as Permission;
106        let supportPermissions = supportPermission();
107        if (supportPermissions.indexOf(permission) == -1) {
108          continue;
109        }
110        try {
111          let flag = await acManager.getPermissionFlags(info.tokenId, permission);
112          if (flag == Constants.PERMISSION_SYSTEM_FIXED) {
113            continue;
114          }
115        } catch (err) {
116          Log.error('getPermissionFlags error: ' + JSON.stringify(err));
117        }
118        this.reqUserPermissions.push(permission);
119      }
120    }
121  }
122
123  async initApplicationInfo(info: AppInfo) {
124    Log.info(`labelResource: ` + JSON.stringify(info.labelResource));
125    let resourceManager = this.context.createBundleContext(info.bundleName).resourceManager;
126
127    if (info.labelResource.id !== 0) {
128      info.label = await this.context.resourceManager.getStringValue(info.labelResource);
129    } else {
130      info.label = await resourceManager.getStringValue(info.labelId);
131    }
132
133    try {
134      if (info.iconResource.id !== 0) {
135        let iconDescriptor = this.context.resourceManager.getDrawableDescriptor(info.iconResource);
136        info.icon = iconDescriptor?.getPixelMap();
137      } else {
138        let iconDescriptor = resourceManager.getDrawableDescriptor(info.iconId);
139        info.icon = iconDescriptor?.getPixelMap();
140      }
141    } catch (error) {
142      Log.error(`getDrawableDescriptor failed, error code: ${error.code}, message: ${error.message}.`);
143    }
144
145    if (!info.icon) {
146      info.icon = $r('app.media.icon');
147    }
148
149    this.reqUserPermissions = [];
150    await this.getReqUserPermissions(info);
151    let groupIds: number[] = [];
152    for (let i = 0; i < this.reqUserPermissions.length; i++) {
153      let groupId = getGroupIdByPermission(this.reqUserPermissions[i])
154      if (groupIds.indexOf(groupId) == -1) {
155        groupIds.push(groupId);
156      }
157    }
158    info.permissions = this.reqUserPermissions;
159    info.groupId = groupIds;
160  }
161
162  /**
163   * Initialize permission status information and group permission information
164   */
165  async initialPermissions() {
166    if (this.bundleName && !this.applicationInfo.groupId.length) {
167      await this.initApplicationInfo(this.applicationInfo);
168    }
169    let reqPermissions = this.applicationInfo.permissions;
170    let reqGroupIds = this.applicationInfo.groupId;
171
172    this.allowedListItem = [];
173    this.bannedListItem = [];
174
175    for (let i = 0; i < reqGroupIds.length; i++) {
176      let id = reqGroupIds[i];
177      let groupName = groups[id].groupName;
178      let group = groups[id].name;
179      let groupReqPermissions: Permissions[] = [];
180      for (let j = 0; j < reqPermissions.length; j++) {
181        let permission = reqPermissions[j];
182        if (groups[id].permissions.indexOf(permission) != -1) {
183          groupReqPermissions.push(permission);
184        }
185      }
186      this.isGranted = group === 'LOCATION' ? Constants.PERMISSION_BAN : Constants.PERMISSION_ALLOW;
187      this.folderStatus = [false, false, false];
188      await this.getStatus(groupReqPermissions, group);
189
190      if (
191        this.isGranted === Constants.PERMISSION_ALLOW || this.isGranted === Constants.PERMISSION_ALLOWED_ONLY_DURING_USE
192      ) {
193        this.allowedListItem.push(new PermissionObj(groupName, groupReqPermissions, group));
194      } else {
195        if (group === 'FOLDER' && this.folderStatus.includes(true)) {
196          this.allowedListItem.push(new PermissionObj(groupName, groupReqPermissions, group));
197        } else {
198          this.bannedListItem.push(new PermissionObj(groupName, groupReqPermissions, group));
199        }
200      }
201
202      GlobalContext.store('folderStatus', this.folderStatus);
203    }
204  }
205
206  async getStatus(groupReqPermissions: Permissions[], group: string) {
207    if (group === 'LOCATION') {
208      try {
209        let acManager = abilityAccessCtrl.createAtManager();
210        let fuzzyState = acManager.verifyAccessTokenSync(
211          this.applicationInfo.tokenId, Permission.APPROXIMATELY_LOCATION
212        );
213        fuzzyState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
214          this.isGranted = Constants.PERMISSION_ALLOWED_ONLY_DURING_USE : null;
215        let backgroundState = acManager.verifyAccessTokenSync(
216          this.applicationInfo.tokenId, Permission.LOCATION_IN_BACKGROUND
217        );
218        backgroundState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ?
219          this.isGranted = Constants.PERMISSION_ALLOW : null;
220        await acManager.getPermissionFlags(this.applicationInfo.tokenId, Permission.APPROXIMATELY_LOCATION )
221        .then(flag => {
222          flag === Constants.PERMISSION_ALLOW_THIS_TIME ? this.isGranted = Constants.PERMISSION_ONLY_THIS_TIME : null;
223        })
224      } catch (err) {
225        Log.error('change location status error: ' + JSON.stringify(err));
226      }
227      GlobalContext.store('locationStatus', this.isGranted);
228      return true;
229    }
230    for (let i = 0; i < groupReqPermissions.length; i++) {
231      let permission = groupReqPermissions[i];
232      let res = await verifyAccessToken(this.applicationInfo.tokenId, permission);
233      if (res != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
234        this.isGranted = Constants.PERMISSION_BAN;
235      }
236      if (group === 'FOLDER' && res === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
237        switch (permission) {
238          case Permission.READ_WRITE_DOWNLOAD_DIRECTORY:
239            this.folderStatus[0] = true;
240            break;
241          case Permission.READ_WRITE_DESKTOP_DIRECTORY:
242            this.folderStatus[1] = true;
243            break;
244          case Permission.READ_WRITE_DOCUMENTS_DIRECTORY:
245            this.folderStatus[2] = true;
246            break;
247        }
248      }
249    }
250    return true;
251  }
252
253  /**
254   * Lifecycle function, triggered once when this page is displayed
255   */
256  onPageShow() {
257    this.initialPermissions();
258    bundleManager.getApplicationInfo(
259      this.applicationInfo.bundleName, bundleManager.ApplicationFlag.GET_APPLICATION_INFO_DEFAULT
260    ).then(appInfo => {
261      let bundleContext = this.context.createBundleContext(this.applicationInfo.bundleName);
262      bundleContext.resourceManager.getStringValue(appInfo.labelId, (error, value) => {
263        if (value) {
264          this.applicationInfo.label = value;
265          GlobalContext.store('applicationInfo', this.applicationInfo);
266          this.label = value
267        }
268      })
269    }).catch((error: BusinessError) => {
270      Log.error('getApplicationInfo error: ' + JSON.stringify(error));
271    })
272  }
273
274  build() {
275    Column() {
276      GridRow({ gutter: Constants.GUTTER, columns: {
277        xs: Constants.XS_COLUMNS, sm: Constants.SM_COLUMNS, md: Constants.MD_COLUMNS, lg: Constants.LG_COLUMNS } }) {
278        GridCol({
279          span: { xs: Constants.XS_SPAN, sm: Constants.SM_SPAN, md: Constants.MD_SPAN, lg: Constants.LG_SPAN },
280          offset: { xs: Constants.XS_OFFSET, sm: Constants.SM_OFFSET, md: Constants.MD_OFFSET, lg: Constants.LG_OFFSET }
281        }) {
282          Row() {
283            Column() {
284              Row() {
285                backBar({ title: JSON.stringify(this.label || this.applicationInfo.label), recordable: false })
286              }
287              Row() {
288                Column() {
289                  if (!this.allowedListItem.length && !this.bannedListItem.length) {
290                    Row() {
291                      List() {
292                        ListItem() {
293                          Row() {
294                            Column() {
295                              Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
296                                Row() {
297                                  Column() {
298                                    Row() {
299                                      Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
300                                        Text($r('app.string.no_permission'))
301                                          .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
302                                          .fontColor($r('sys.color.font_primary'))
303                                      }.margin({ top: Constants.FLEX_MARGIN_TOP, bottom: Constants.FLEX_MARGIN_BOTTOM })
304                                    }.height(Constants.FULL_HEIGHT)
305                                  }.flexGrow(Constants.FLEX_GROW)
306                                   .constraintSize({minHeight: Constants.CONSTRAINTSIZE_MINHEIGHT })
307                                }
308                                .width(Constants.FULL_WIDTH)
309                                .height(Constants.LISTITEM_ROW_HEIGHT)
310                              }
311                            }
312                          }
313                        }.padding({ left: Constants.LISTITEM_PADDING_LEFT, right: Constants.LISTITEM_PADDING_RIGHT })
314                      }
315                      .backgroundColor($r('sys.color.comp_background_list_card'))
316                      .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
317                      .padding({ top: Constants.LIST_PADDING_TOP, bottom: Constants.LIST_PADDING_BOTTOM })
318                    }.margin({ top: Constants.ROW_MARGIN_TOP })
319                     .padding({
320                       left: Constants.SECONDARY_LIST_PADDING_LEFT,
321                       right: Constants.SECONDARY_LIST_PADDING_RIGHT
322                     })
323                  } else {
324                    Scroll() {
325                      List() {
326                        if (this.allowedListItem.length) {
327                          ListItem() {
328                            Row() {
329                              Text($r('app.string.allowed'))
330                                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
331                                .fontColor($r('sys.color.font_secondary'))
332                                .fontWeight(FontWeight.Medium)
333                                .lineHeight(Constants.SUBTITLE_LINE_HEIGHT)
334                            }.constraintSize({ minHeight: Constants.SUBTITLE_MIN_HEIGHT })
335                            .width(Constants.FULL_WIDTH)
336                            .padding({ top: Constants.SUBTITLE_PADDING_TOP, bottom: Constants.SUBTITLE_PADDING_BOTTOM,
337                              left: Constants.SECONDARY_TEXT_MARGIN_LEFT})
338                          }
339
340                          ListItem() {
341                            Row() {
342                              List() {
343                                ForEach(this.allowedListItem, (item: PermissionObj) => {
344                                  this.ListItemLayout(item, Constants.PERMISSION_ALLOW)
345                                }, (item: PermissionObj) => JSON.stringify(item))
346                              }
347                              .backgroundColor($r('sys.color.comp_background_list_card'))
348                              .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
349                              .padding(Constants.LIST_PADDING_TOP)
350                              .divider({
351                                strokeWidth: Constants.DIVIDER,
352                                color: $r('sys.color.comp_divider'),
353                                startMargin: Constants.DEFAULT_MARGIN_START,
354                                endMargin: Constants.DEFAULT_MARGIN_END
355                              })
356                            }.margin({ top: Constants.ROW_MARGIN_TOP })
357                            .padding({
358                              left: Constants.SECONDARY_LIST_PADDING_LEFT,
359                              right: Constants.SECONDARY_LIST_PADDING_RIGHT
360                            })
361                          }
362                        }
363                        if (this.bannedListItem.length) {
364                          ListItem() {
365                            Row() {
366                              Text($r('app.string.banned'))
367                                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
368                                .fontColor($r('sys.color.font_secondary'))
369                                .fontWeight(FontWeight.Medium)
370                                .lineHeight(Constants.SUBTITLE_LINE_HEIGHT)
371                            }.constraintSize({ minHeight: Constants.SUBTITLE_MIN_HEIGHT })
372                            .width(Constants.FULL_WIDTH)
373                            .padding({ top: Constants.SUBTITLE_PADDING_TOP, bottom: Constants.SUBTITLE_PADDING_BOTTOM,
374                              left: Constants.SECONDARY_TEXT_MARGIN_LEFT})
375                          }
376
377                          ListItem() {
378                            Row() {
379                              List() {
380                                ForEach(this.bannedListItem, (item: PermissionObj) => {
381                                  this.ListItemLayout(item, Constants.PERMISSION_BAN)
382                                }, (item: PermissionObj) => JSON.stringify(item))
383                              }
384                              .backgroundColor($r('sys.color.comp_background_list_card'))
385                              .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
386                              .padding(Constants.LIST_PADDING_TOP)
387                              .divider({
388                                strokeWidth: Constants.DIVIDER,
389                                color: $r('sys.color.comp_divider'),
390                                startMargin: Constants.DEFAULT_MARGIN_START,
391                                endMargin: Constants.DEFAULT_MARGIN_END
392                              })
393                            }.margin({ top: Constants.ROW_MARGIN_TOP })
394                            .padding({
395                              left: Constants.SECONDARY_LIST_PADDING_LEFT,
396                              right: Constants.SECONDARY_LIST_PADDING_RIGHT
397                            })
398                          }
399                        }
400                      }
401                    }.scrollBar(BarState.Off)
402                  }
403                }
404                .width(Constants.FULL_WIDTH)
405                .height(Constants.FULL_HEIGHT)
406              }
407              .layoutWeight(Constants.LAYOUT_WEIGHT)
408            }
409          }
410          .height(Constants.FULL_HEIGHT)
411          .width(Constants.FULL_WIDTH)
412          .backgroundColor($r('sys.color.background_secondary'))
413        }
414      }.backgroundColor($r('sys.color.background_secondary'))
415    }
416  }
417}
418