• 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 { alphabetIndexerComponent } from '../common/components/alphabeticalIndex';
18import { textInput } from '../common/components/search';
19import router from '@ohos.router';
20import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
21import { BusinessError } from '@ohos.base';
22import { Log, verifyAccessToken, indexValue, sortByName } from '../common/utils/utils';
23import {
24  ApplicationObj,
25  PermissionInfo,
26  RouterParams2,
27  PermissionApplications,
28  AppInfo
29} from '../common/model/typedef';
30import { GlobalContext } from '../common/utils/globalContext';
31import Constants from '../common/utils/constant';
32import { permissionInfos } from '../common/model/permissionGroup';
33import { Permission } from '../common/model/definition';
34
35@Extend(Image)function customizeImage(width: number, height: number) {
36  .objectFit(ImageFit.Contain)
37  .width(width)
38  .height(height)
39}
40
41@Entry
42@Component
43struct locationInfoPage {
44  private backTitle: ResourceStr = (router.getParams() as RouterParams2).backTitle;
45
46  build() {
47    GridRow({ gutter: Constants.GUTTER, columns: {
48      xs: Constants.XS_COLUMNS, sm: Constants.SM_COLUMNS, md: Constants.MD_COLUMNS, lg: Constants.LG_COLUMNS } }) {
49      GridCol({
50        span: { xs: Constants.XS_SPAN, sm: Constants.SM_SPAN, md: Constants.MD_SPAN, lg: Constants.LG_SPAN },
51        offset: { xs: Constants.XS_OFFSET, sm: Constants.SM_OFFSET, md: Constants.MD_OFFSET, lg: Constants.LG_OFFSET }
52      }) {
53        Row() {
54          Column() {
55            Row() {
56              backBar({ title: JSON.stringify(this.backTitle), recordable: false })
57            }
58            Row() {
59              Column() {
60                applicationItem()
61
62              }.width(Constants.FULL_WIDTH)
63            }
64            .layoutWeight(Constants.LAYOUT_WEIGHT)
65          }
66        }
67        .height(Constants.FULL_HEIGHT)
68        .width(Constants.FULL_WIDTH)
69        .backgroundColor($r('sys.color.background_secondary'))
70      }
71    }.backgroundColor($r('sys.color.background_secondary'))
72  }
73}
74
75@Component
76struct applicationItem {
77  private list: PermissionApplications[] = (router.getParams() as RouterParams2).list;
78  private permissionName: Permission = (router.getParams() as RouterParams2).permissionName;
79  @State permissionNum: number = Constants.PERMISSION_NUM; // permission num
80  @State toggleIsOn: boolean[] = []; // toggle switch state array
81  @State isRisk: boolean[] = [];
82  @State isFirst: boolean[] = [];
83  @State applicationList: ApplicationObj[] = []; // application info array
84  @State searchResult: boolean = true; // search results
85  @State selectedIndex: number = 0;
86  @State permissionInfo: PermissionInfo | undefined = undefined;
87  @State allBundleInfo: AppInfo[] = GlobalContext.load('allBundleInfo');
88  scroller: Scroller = new Scroller();
89
90  @Builder ListItemLayout(item: ApplicationObj) {
91    ListItem() {
92      Row() {
93        Column() {
94          Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
95            Row() {
96              Image(item.icon)
97                .customizeImage(Constants.AUTHORITY_IMAGE_WIDTH, Constants.AUTHORITY_IMAGE_HEIGHT)
98                .margin({ right: Constants.AUTHORITY_IMAGE_MARGIN_RIGHT })
99              Column() {
100                Text(item.label)
101                  .width(Constants.MAXIMUM_HEADER_WIDTH)
102                  .maxLines(Constants.MAXIMUM_HEADER_LINES)
103                  .textOverflow({ overflow: TextOverflow.Ellipsis })
104                  .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
105                  .fontWeight(FontWeight.Medium)
106                  .fontColor($r('sys.color.font_primary'))
107                if (this.isRisk[item.index]) {
108                  Text($r('app.string.risk_warning'))
109                    .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
110                    .fontColor($r('sys.color.font_secondary'))
111                }
112              }.flexGrow(Constants.FLEX_GROW)
113              .alignItems(HorizontalAlign.Start)
114              Toggle({ type: ToggleType.Switch, isOn: this.toggleIsOn[item.index] })
115                .selectedColor($r('sys.color.icon_emphasize'))
116                .switchPointColor($r('sys.color.comp_background_primary_contrary'))
117                .padding({ right: 0 })
118                .width(Constants.AUTHORITY_TOGGLE_WIDTH)
119                .height(Constants.AUTHORITY_TOGGLE_HEIGHT)
120                .onChange((isOn: boolean) => {
121                  if (item.permission === undefined) {
122                    return;
123                  }
124                  if (this.isFirst[item.index] && isOn) {
125                    this.isFirst[item.index] = false;
126                    return;
127                  }
128                  this.isFirst[item.index] = false;
129                  if (isOn) {
130                    this.grantUserGrantedPermission(item.accessTokenId, item.permission, item.index);
131                  } else {
132                    this.revokeUserGrantedPermission(item.accessTokenId, item.permission, item.index);
133                  }
134                })
135            }
136            .width(Constants.FULL_WIDTH)
137            .height(Constants.AUTHORITY_ROW_HEIGHT)
138            .constraintSize({ minHeight: Constants.AUTHORITY_CONSTRAINTSIZE_MINHEIGHT })
139          }
140        }.onClick(() => {
141        })
142      }
143    }.padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
144    .enabled(!this.isRisk[item.index])
145    .opacity(this.isRisk[item.index] ? $r('sys.float.ohos_id_alpha_disabled') : 1)
146  }
147
148  /**
149   * Grant permissions to the app
150   * @param {Number} accessTokenId
151   * @param {String} permission permission name
152   * @param {Number} index Array index to modify permission status
153   */
154  grantUserGrantedPermission(accessTokenId: number, permission: Permissions, index: number) {
155    abilityAccessCtrl.createAtManager().grantUserGrantedPermission(
156      accessTokenId, permission, Constants.PERMISSION_FLAG).then(() => {
157      // result: 0 Authorization succeeded; result: -1 Authorization failed
158      this.toggleIsOn[index] = true;
159      let num = this.toggleIsOn.filter(item => item === true).length;
160      this.permissionNum = num;
161    }).catch((error: BusinessError) => {
162      this.toggleIsOn[index] = false;
163      Log.error('grantUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
164    })
165  }
166
167  /**
168   * Deauthorize the app
169   * @param {Number} accessTokenId
170   * @param {String} permission permission name
171   * @param {Number} index Array index to modify permission status
172   */
173  revokeUserGrantedPermission(accessTokenId: number, permission: Permissions, index: number) {
174    abilityAccessCtrl.createAtManager().revokeUserGrantedPermission(
175      accessTokenId, permission, Constants.PERMISSION_FLAG).then(() => {
176      // result: 0 successfully cancel the authorization; result: -1 cancel the authorization failed
177      this.toggleIsOn[index] = false;
178      let num = this.toggleIsOn.filter(item => item === true).length;
179      this.permissionNum = num;
180    }).catch(() => {
181      this.toggleIsOn[index] = true;
182    })
183  }
184
185  /**
186   * Lifecycle function, executed when the page is initialized
187   */
188  aboutToAppear() {
189    let bundleNames = this.list.length > 0 ? this.list[0].bundleNames : this.list;
190    this.permissionInfo = permissionInfos.get(this.permissionName);
191
192    let atManager = abilityAccessCtrl.createAtManager();
193    for (let i = 0; i < bundleNames.length; i++) {
194      // Get BundleInfo based on bundle name
195      this.allBundleInfo.forEach(bundleInfo => {
196        if (bundleInfo.bundleName === bundleNames[i]) {
197          this.applicationList.push(
198            new ApplicationObj(
199              bundleInfo.label,
200              bundleInfo.icon,
201              i,
202              bundleInfo.tokenId,
203              this.list[0].permission,
204              bundleInfo.zhTag,
205              bundleInfo.indexTag,
206              bundleInfo.language) // Get the first letter in the returned initials array
207          );
208          verifyAccessToken(bundleInfo.tokenId, this.list[0].permission).then(data => {
209            // 0: have permission; -1: no permission
210            if (data === Constants.PERMISSION_INDEX) {
211              this.toggleIsOn[i] = true;
212              this.isFirst[i] = true;
213              this.permissionNum++;
214            } else {
215              this.toggleIsOn[i] = false;
216              this.isFirst[i] = false;
217            }
218          })
219          this.isRisk[i] = false;
220          try {
221            atManager.getPermissionFlags(bundleInfo.tokenId, this.list[0].permission).then(data => {
222              if (data == Constants.PERMISSION_POLICY_FIXED) {
223                this.isRisk[i] = true;
224              }
225            })
226          } catch (err) {
227            Log.error('getPermissionFlags error: ' + JSON.stringify(err));
228          }
229        }
230      })
231    }
232  }
233
234  build() {
235    Column() {
236      Row() {
237        textInput({
238          applicationItem: $applicationList,
239          searchResult: $searchResult
240        })
241      }.padding({
242        left: Constants.AUTHORITY_TEXTINPUT_PADDING_LEFT,
243        right: Constants.AUTHORITY_TEXTINPUT_PADDING_RIGHT
244      })
245      Flex({ alignItems:ItemAlign.Start, justifyContent: FlexAlign.Start }) {
246        Column() {
247          Flex({ justifyContent: FlexAlign.Start }) {
248            if (this.permissionNum > 0) {
249              Text(
250                this.permissionInfo?.enableDescription ?
251                $r(this.permissionInfo.enableDescription, String(this.permissionNum)) :
252                ''
253              )
254                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
255                .fontColor($r('sys.color.font_secondary'))
256                .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP })
257            } else {
258              Text(this.permissionInfo?.forbiddenDescription)
259                .fontSize(Constants.TEXT_SMALL_FONT_SIZE)
260                .fontColor($r('sys.color.font_secondary'))
261                .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP })
262            }
263          }.padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
264          .margin({ bottom: Constants.AUTHORITY_ROW_MARGIN_BOTTOM })
265          Row() {
266            Column() {
267              if (!this.applicationList.length) {
268                if (this.searchResult) {
269                  Row() {}
270                } else {
271                  Row() {
272                    Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
273                      Image($r('app.media.searchnoresult'))
274                        .customizeImage(Constants.SEARCHNORESULT_IMAGE_WIDTH, Constants.SEARCHNORESULT_IMAGE_HEIGHT)
275                    }
276                  }
277                }
278              } else {
279                Row() {
280                  List({ scroller: this.scroller }) {
281                    ForEach(sortByName(this.applicationList), (item: ApplicationObj) => {
282                      this.ListItemLayout(item)
283                    }, (item: ApplicationObj) => JSON.stringify(item))
284                  }
285                  .backgroundColor($r('sys.color.comp_background_list_card'))
286                  .borderRadius($r('sys.float.ohos_id_corner_radius_card'))
287                  .padding({ top: Constants.LIST_PADDING_TOP, bottom: Constants.LIST_PADDING_BOTTOM })
288                  .divider({
289                    strokeWidth: Constants.DIVIDER,
290                    color: $r('sys.color.comp_divider'),
291                    startMargin: Constants.DIVIDER_MARGIN_RIGHT_APPLICATION,
292                    endMargin: Constants.DEFAULT_MARGIN_END
293                  })
294                  .onScrollIndex((start, end) => {
295                    GlobalContext.getContext().set('scroller', this.scroller);
296                    if (this.applicationList.length > 0) {
297                      let alphabeticalIndex = sortByName(this.applicationList)[start].indexTag;
298                      let index = indexValue.indexOf(alphabeticalIndex);
299                      this.selectedIndex = index >= 0 ? index : 0;
300                    }
301                  })
302                }
303              }
304            }.width(Constants.FULL_WIDTH)
305            .margin({ bottom: Constants.AUTHORITY_LIST_MARGIN_BOTTOM })
306          }
307        }.padding({ left: Constants.AUTHORITY_LISTITEM_PADDING_LEFT })
308        Column() {
309          alphabetIndexerComponent({ applicationItem: $applicationList, index: $selectedIndex })
310        }.width(Constants.AUTHORITY_ALPHABETINDEX_WIDTH)
311         .padding({ top: Constants.AUTHORITY_ALPHABETINDEX_PADDING_TOP })
312        .margin({ bottom: Constants.APPLICATION_LIST_MARGIN_BOTTOM })
313      }.flexGrow(Constants.FLEX_GROW)
314    }.height(Constants.FULL_HEIGHT)
315  }
316}
317