• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2022 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 bundle from "@ohos.bundle";
21import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
22import { getAppLabel, getAppIcon, verifyAccessToken } from "../common/utils/utils";
23import { makePy } from "../common/utils/utils";
24import { authorizeDialog } from "../common/components/dialog";
25import Constants from '../common/utils/constant';
26
27var TAG = 'PermissionManager_MainAbility:'
28
29@Extend(Image) function customizeImage(width: number, height: number) {
30  .objectFit(ImageFit.Contain)
31  .width(width)
32  .height(height)
33}
34
35let routerData: any = router.getParams()['routerData']; // Routing jump data
36let backTitle = router.getParams()['backTitle']; // return title name
37class ApplicationObj {
38  labelId: string
39  iconId: string
40  index: number
41  accessTokenId: number
42  permission: string
43  alphabeticalIndex: string
44  constructor(
45    labelId: string,
46    iconId: string,
47    index: number,
48    accessTokenId: number,
49    permission: string,
50    alphabeticalIndex: string) {
51    this.labelId = labelId
52    this.iconId = iconId
53    this.index = index
54    this.accessTokenId = accessTokenId
55    this.permission = permission
56    this.alphabeticalIndex = alphabeticalIndex
57  }
58} // application information
59
60@Entry
61@Component
62struct locationInfoPage {
63  build() {
64    GridContainer({ gutter: Constants.GUTTER, margin: Constants.GRID_MARGIN }) {
65      Row() {
66        Row()
67          .useSizeType({
68            xs: { span: Constants.LEFT_XS_SPAN, offset: Constants.LEFT_XS_OFFSET },
69            sm: { span: Constants.LEFT_SM_SPAN, offset: Constants.LEFT_SM_OFFSET },
70            md: { span: Constants.LEFT_MD_SPAN, offset: Constants.LEFT_MD_OFFSET },
71            lg: { span: Constants.LEFT_LG_SPAN, offset: Constants.LEFT_LG_OFFSET }
72          })
73          .height(Constants.FULL_HEIGHT)
74        Row() {
75          Column() {
76            Row() {
77              backBar({ title: JSON.stringify(backTitle), recordable: false })
78            }
79            Row() {
80              Column() {
81                applicationItem()
82
83              }.width(Constants.FULL_WIDTH)
84            }
85            .layoutWeight(Constants.LAYOUT_WEIGHT)
86          }
87        }
88        .useSizeType({
89          xs: { span: Constants.MIDDLE_XS_SPAN, offset: Constants.MIDDLE_XS_OFFSET },
90          sm: { span: Constants.MIDDLE_SM_SPAN, offset: Constants.MIDDLE_SM_OFFSET },
91          md: { span: Constants.MIDDLE_MD_SPAN, offset: Constants.MIDDLE_MD_OFFSET },
92          lg: { span: Constants.MIDDLE_LG_SPAN, offset: Constants.MIDDLE_LG_OFFSET }
93        })
94        .height(Constants.FULL_HEIGHT)
95        Row()
96          .useSizeType({
97            xs: { span: Constants.RIGHT_XS_SPAN, offset: Constants.RIGHT_XS_OFFSET },
98            sm: { span: Constants.RIGHT_SM_SPAN, offset: Constants.RIGHT_SM_OFFSET },
99            md: { span: Constants.RIGHT_MD_SPAN, offset: Constants.RIGHT_MD_OFFSET },
100            lg: { span: Constants.RIGHT_LG_SPAN, offset: Constants.RIGHT_LG_OFFSET }
101          })
102          .height(Constants.FULL_HEIGHT)
103      }
104      .height(Constants.FULL_HEIGHT)
105      .width(Constants.FULL_WIDTH)
106      .backgroundColor($r("sys.color.ohos_id_color_sub_background"))
107    }
108  }
109}
110
111@Component
112struct applicationItem {
113  @State permissionNum: number = Constants.PERMISSION_NUM; // permission num
114  @State toggleIsOn: object = {}; // toggle switch state array
115  @State applicationList: ApplicationObj[] = []; // application info array
116  @State searchResult: boolean = true; // search results
117  @State placeholder: string = ''
118
119  authorizeDialogController: CustomDialogController = new CustomDialogController({
120    builder: authorizeDialog({ }),
121    autoCancel: true,
122    alignment: DialogAlignment.Center
123  });
124
125  @Builder ListItemLayout(item, index) {
126    ListItem() {
127      Row() {
128        Column() {
129          Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
130            Row() {
131              Image(item.iconId)
132                .customizeImage(Constants.AUTHORITY_IMAGE_WIDTH, Constants.AUTHORITY_IMAGE_HEIGHT)
133                .margin({ right: Constants.AUTHORITY_IMAGE_MARGIN_RIGHT })
134              Text(item.labelId)
135                .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
136                .fontWeight(FontWeight.Medium)
137                .fontColor($r('app.color.label_color'))
138                .flexGrow(Constants.FLEX_GROW)
139              Toggle({ type: ToggleType.Switch, isOn: this.toggleIsOn[item.index] })
140                .selectedColor($r('app.color.button_color'))
141                .padding({ right: 0 })
142                .width(Constants.AUTHORITY_TOGGLE_WIDTH)
143                .height(Constants.AUTHORITY_TOGGLE_HEIGHT)
144                .onChange((isOn: boolean) => {
145                  if (item.accessTokenId === '' || item.permission === '') {
146                    return;
147                  }
148                  if (isOn) {
149                    this.grantUserGrantedPermission(item.accessTokenId, item.permission, item.index);
150                  } else {
151                    this.revokeUserGrantedPermission(item.accessTokenId, item.permission, item.index);
152                  }
153                })
154            }
155            .width(Constants.FULL_WIDTH)
156            .height(Constants.AUTHORITY_ROW_HEIGHT)
157            .constraintSize({ minHeight: Constants.AUTHORITY_CONSTRAINTSIZE_MINHEIGHT })
158          }
159          if (!index) {
160            Row() {
161              Flex() {
162                Column().width(Constants.APPLICATION_TEXT_DECORATION_MARGIN_LEFT)
163                Column()
164                  .backgroundColor($r('app.color.text_decoration_color'))
165                  .height(Constants.TEXT_DECORATION_HEIGHT)
166                  .flexGrow(Constants.FLEX_GROW)
167              }
168            }
169          }
170        }.onClick(() => {
171        })
172      }
173    }.padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
174  }
175
176  /**
177   * Grant permissions to the app
178   * @param {Number} accessTokenId
179   * @param {String} permission permission name
180   * @param {Number} index Array index to modify permission status
181   */
182  grantUserGrantedPermission(accessTokenId, permission, index) {
183    abilityAccessCtrl.createAtManager().grantUserGrantedPermission(
184      accessTokenId, permission, Constants.PERMISSION_FLAG).then(() => {
185      // result: 0 Authorization succeeded; result: -1 Authorization failed
186      this.toggleIsOn[index] = true;
187      let num = Constants.PERMISSION_NUM;
188      for(let key in this.toggleIsOn){
189        if(this.toggleIsOn[key]){
190          num++;
191        }
192      }
193      this.permissionNum = num;
194    }).catch(error => {
195        this.authorizeDialogController.open();
196        this.toggleIsOn[index] = false;
197        setTimeout(()=> {
198          this.authorizeDialogController.close();
199        }, Constants.DELAY_TIME)
200      console.error(TAG + 'abilityAccessCtrl.createAtManager.grantUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
201    })
202  }
203
204  /**
205   * Deauthorize the app
206   * @param {Number} accessTokenId
207   * @param {String} permission permission name
208   * @param {Number} index Array index to modify permission status
209   */
210  revokeUserGrantedPermission(accessTokenId, permission, index) {
211    abilityAccessCtrl.createAtManager().revokeUserGrantedPermission(
212      accessTokenId, permission, Constants.PERMISSION_FLAG).then(() => {
213      // result: 0 successfully cancel the authorization; result: -1 cancel the authorization failed
214      this.toggleIsOn[index] = false;
215      let num = Constants.PERMISSION_NUM;
216      for(let key in this.toggleIsOn){
217        if(this.toggleIsOn[key]){
218          num++;
219        }
220      }
221      this.permissionNum = num;
222    }).catch(() => {
223        this.authorizeDialogController.open();
224        this.toggleIsOn[index] = true;
225        setTimeout(()=> {
226          this.authorizeDialogController.close();
227        }, Constants.DELAY_TIME)
228    })
229  }
230
231  /**
232   * Lifecycle function, executed when the page is initialized
233   */
234  aboutToAppear() {
235    let bundleNames = routerData.length > 0 ? routerData[0].bundleNames : routerData;
236
237    globalThis.context.resourceManager.getString($r("app.string.textInput_placeholder").id).then(val => {
238      this.placeholder = val
239    })
240
241    // initial then fill values when sync return which may cause sync panic
242    for (let i = 0; i < bundleNames.length; i++) {
243      this.applicationList.push(new ApplicationObj('', '', i, 0, '', ''));
244    }
245
246    for (let i = 0; i < bundleNames.length; i++) {
247      // Get BundleInfo based on bundle name
248      bundle.getBundleInfo(bundleNames[i], Constants.PARMETER_BUNDLE_FLAG).then(res => {
249        Promise.all([getAppLabel(res.appInfo.labelId, res.name),
250          getAppIcon(res.appInfo.iconId, res.name),
251          verifyAccessToken(res.appInfo.accessTokenId, routerData[0].permission)])
252          .then((values) => {
253          this.applicationList[i] = (
254            new ApplicationObj(
255              String(values[0]),
256              String(values[1]),
257              i,
258              res.appInfo.accessTokenId,
259              routerData[0].permission,
260              makePy(values[0])[0].slice(0, 1)) // Get the first letter in the returned initials array
261          );
262          // 0: have permission; -1: no permission
263          if (values[2] === Constants.PERMISSION_INDEX) {
264            this.toggleIsOn[i] = true;
265            this.permissionNum++;
266          } else {
267            this.toggleIsOn[i] = false;
268          }
269          });
270      }).catch(error => {
271        console.log(TAG + bundleNames[i] + "getBundleInfo failed, cause: " + JSON.stringify(error));
272      })
273    }
274  }
275
276  build() {
277    Column() {
278      Row() {
279        textInput({
280          placeholder: this.placeholder,
281          applicationItem: $applicationList,
282          searchResult: $searchResult
283        })
284      }.padding({
285        left: Constants.AUTHORITY_TEXTINPUT_PADDING_LEFT,
286        right: Constants.AUTHORITY_TEXTINPUT_PADDING_RIGHT
287      })
288      Flex({ alignItems:ItemAlign.Start, justifyContent: FlexAlign.Start }) {
289        Column() {
290          Flex({ justifyContent: FlexAlign.Start }) {
291            Text(String(this.permissionNum))
292              .fontSize(Constants.TEXT_SMAL_FONT_SIZE)
293              .fontColor($r('app.color.secondary_font_color'))
294              .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP, left: Constants.AUTHORITY_TEXT_MARGIN_LEFT })
295            Text($r('app.string.number_of_authorized_applications'))
296              .fontSize(Constants.TEXT_SMAL_FONT_SIZE)
297              .fontColor($r('app.color.secondary_font_color'))
298              .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP, left: Constants.AUTHORITY_TEXT_MARGIN_LEFT })
299          }.padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
300          .margin({ bottom: Constants.AUTHORITY_ROW_MARGIN_BOTTOM })
301          Scroll() {
302            Row() {
303              Column() {
304                if (!this.applicationList.length) {
305                  if (this.searchResult) {
306                    Row() {}
307                  } else {
308                    Row() {
309                      Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
310                        Image($r('app.media.searchnoresult'))
311                          .customizeImage(Constants.SEARCHNORESULT_IMAGE_WIDTH, Constants.SEARCHNORESULT_IMAGE_HEIGHT)
312                      }
313                    }
314                  }
315                } else {
316                  Row() {
317                    List() {
318                      ForEach(this.applicationList.slice(Constants.SLICE_START, this.applicationList.length - 1),
319                      (item) => {
320                        this.ListItemLayout(item, Constants.SLICE_START_INDEX)
321                      }, item => item.toString())
322                      ForEach(this.applicationList.slice(Constants.SLICE_END), (item) => {
323                        this.ListItemLayout(item, Constants.SLICE_END_INDEX)
324                      }, item => item.toString())
325                    }
326                    .backgroundColor($r('app.color.default_background_color'))
327                    .borderRadius(Constants.BORDER_RADIUS)
328                    .padding({ top: Constants.LIST_PADDING_TOP, bottom: Constants.LIST_PADDING_BOTTOM })
329                  }
330                }
331              }.width(Constants.FULL_WIDTH)
332              .margin({ bottom: Constants.AUTHORITY_LIST_MARGIN_BOTTOM })
333            }
334          }.scrollBar(BarState.Off)
335          .borderRadius(Constants.BORDER_RADIUS)
336        }.padding({ left: Constants.AUTHORITY_LISTITEM_PADDING_LEFT })
337        Column() {
338          alphabetIndexerComponent({ applicationItem: $applicationList })
339        }.width(Constants.AUTHORITY_ALPHABETINDEX_WIDTH)
340         .padding({ top: Constants.AUTHORITY_ALPHABETINDEX_PADDING_TOP })
341      }.flexGrow(Constants.FLEX_GROW)
342    }.height(Constants.FULL_HEIGHT)
343  }
344}
345