• 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 audio from '@ohos.multimedia.audio'
23import camera from '@ohos.multimedia.camera'
24import { getAppLabel, getAppIcon, verifyAccessToken} from "../common/utils/utils";
25import { makePy } from "../common/utils/utils";
26import { globalDialog } from "../common/components/dialog";
27import Constants from '../common/utils/constant';
28import { polymorphismGroup, globalGroup } from "../common/model/permissionGroup";
29
30var TAG = 'PermissionManager_MainAbility:'
31
32@Extend(Image) function customizeImage(width: number, height: number) {
33  .objectFit(ImageFit.Contain)
34  .width(width)
35  .height(height)
36}
37
38let routerData: any = router.getParams()['routerData']; // Routing jump data
39let backTitle = router.getParams()['backTitle']; // return title name
40const FUZZY_LOCATION_PERMISSION = 'ohos.permission.APPROXIMATELY_LOCATION'
41const PRECISE_LOCATION_PERMISSION = 'ohos.permission.LOCATION'
42let globalIsOn: any = router.getParams()['globalIsOn']; // return title name
43
44class ApplicationObj {
45  labelId: string
46  iconId: string
47  index: number
48  accessTokenId: number
49  permission: string
50  alphabeticalIndex: string
51  constructor(
52    labelId: string,
53    iconId: string,
54    index: number,
55    accessTokenId: number,
56    permission: string,
57    alphabeticalIndex: string) {
58    this.labelId = labelId
59    this.iconId = iconId
60    this.index = index
61    this.accessTokenId = accessTokenId
62    this.permission = permission
63    this.alphabeticalIndex = alphabeticalIndex
64  }
65} // application information
66
67@Entry
68@Component
69struct locationInfoPage {
70  @State polymorphismIsOn: Array<boolean> = []
71
72  build() {
73    GridContainer({ gutter: Constants.GUTTER, margin: Constants.GRID_MARGIN }) {
74      Row() {
75        Row()
76          .useSizeType({
77            xs: { span: Constants.LEFT_XS_SPAN, offset: Constants.LEFT_XS_OFFSET },
78            sm: { span: Constants.LEFT_SM_SPAN, offset: Constants.LEFT_SM_OFFSET },
79            md: { span: Constants.LEFT_MD_SPAN, offset: Constants.LEFT_MD_OFFSET },
80            lg: { span: Constants.LEFT_LG_SPAN, offset: Constants.LEFT_LG_OFFSET }
81          })
82          .height(Constants.FULL_HEIGHT)
83        Row() {
84          Column() {
85            Row() {
86              backBar({ title: JSON.stringify(backTitle), recordable: false })
87            }
88            Row() {
89              Column() {
90                applicationItem({ polymorphismIsOn: $polymorphismIsOn })
91
92              }.width(Constants.FULL_WIDTH)
93            }
94            .layoutWeight(Constants.LAYOUT_WEIGHT)
95          }
96        }
97        .useSizeType({
98          xs: { span: Constants.MIDDLE_XS_SPAN, offset: Constants.MIDDLE_XS_OFFSET },
99          sm: { span: Constants.MIDDLE_SM_SPAN, offset: Constants.MIDDLE_SM_OFFSET },
100          md: { span: Constants.MIDDLE_MD_SPAN, offset: Constants.MIDDLE_MD_OFFSET },
101          lg: { span: Constants.MIDDLE_LG_SPAN, offset: Constants.MIDDLE_LG_OFFSET }
102        })
103        .height(Constants.FULL_HEIGHT)
104        Row()
105          .useSizeType({
106            xs: { span: Constants.RIGHT_XS_SPAN, offset: Constants.RIGHT_XS_OFFSET },
107            sm: { span: Constants.RIGHT_SM_SPAN, offset: Constants.RIGHT_SM_OFFSET },
108            md: { span: Constants.RIGHT_MD_SPAN, offset: Constants.RIGHT_MD_OFFSET },
109            lg: { span: Constants.RIGHT_LG_SPAN, offset: Constants.RIGHT_LG_OFFSET }
110          })
111          .height(Constants.FULL_HEIGHT)
112      }
113      .height(Constants.FULL_HEIGHT)
114      .width(Constants.FULL_WIDTH)
115      .backgroundColor($r("sys.color.ohos_id_color_sub_background"))
116    }
117  }
118
119  onPageShow() {
120    console.log(TAG + "onPageShow");
121    if (polymorphismGroup.indexOf(globalThis.currentPermissionGroup) !== -1) {
122      var bundleNames = []
123      routerData.forEach(permissionmanager => {
124        permissionmanager.bundleNames.forEach( bundleName => {
125          if (bundleNames.indexOf(bundleName) == -1) {
126            bundleNames.push(bundleName)
127          }
128        })
129      })
130
131      bundleNames.forEach((bundleName, index) => {
132        bundle.getBundleInfo(bundleName, Constants.PARMETER_BUNDLE_FLAG).then(res => {
133          // 0: have permission; -1: no permission
134          this.polymorphismIsOn[index] = true
135          for (let j = 0; j < routerData.length; j++) {
136            if ((routerData[j].permission == PRECISE_LOCATION_PERMISSION) && (res.targetVersion >= Constants.API_VERSION_SUPPORT_STAGE)) {
137              continue
138            }
139            if ((routerData[j].permission == FUZZY_LOCATION_PERMISSION) && (res.targetVersion < Constants.API_VERSION_SUPPORT_STAGE)) {
140              continue
141            }
142            if (res.reqPermissions.indexOf(routerData[j].permission) == -1) {
143              continue
144            }
145            verifyAccessToken(res.appInfo.accessTokenId, routerData[j].permission).then((access) => {
146              if (Number(access) === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
147                this.polymorphismIsOn[index] = false;
148              }
149            });
150          }
151        }).catch(error => {
152          console.log(TAG + bundleName + "onPageShow getBundleInfo failed, cause: " + JSON.stringify(error));
153        })
154      })
155    }
156  }
157}
158
159@Component
160struct applicationItem {
161  @State permissionNum: number = Constants.PERMISSION_NUM; // permission num
162  @State toggleIsOn: object = {}; // toggle switch state array
163  @State applicationList: ApplicationObj[] = []; // application info array
164  @State searchResult: boolean = true; // search results
165  @State placeholder: string = ''
166  @State bundleNameGroup: Array<string> = []
167  @Link polymorphismIsOn: Array<boolean>
168  @State globalIsOn: boolean = true
169
170  privacyDialogController: CustomDialogController = new CustomDialogController({
171    builder: globalDialog({ globalIsOn: $globalIsOn }),
172    autoCancel: false,
173    alignment: DialogAlignment.Center,
174    customStyle: true
175  })
176
177  @Builder ListItemLayout(item, index) {
178    ListItem() {
179      Row() {
180        Column() {
181          Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
182            Row() {
183              Image(item.iconId)
184                .customizeImage(Constants.AUTHORITY_IMAGE_WIDTH, Constants.AUTHORITY_IMAGE_HEIGHT)
185                .margin({ right: Constants.AUTHORITY_IMAGE_MARGIN_RIGHT })
186              Text(item.labelId)
187                .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
188                .fontColor($r('app.color.text_color'))
189                .fontWeight(FontWeight.Medium)
190                .flexGrow(Constants.FLEX_GROW)
191              if (polymorphismGroup.indexOf(globalThis.currentPermissionGroup) == -1) {
192                Toggle({ type: ToggleType.Switch, isOn: this.toggleIsOn[item.index] })
193                  .selectedColor($r('app.color.button_color'))
194                  .padding({ right: 0 })
195                  .width(Constants.AUTHORITY_TOGGLE_WIDTH)
196                  .height(Constants.AUTHORITY_TOGGLE_HEIGHT)
197                  .onChange((isOn: boolean) => {
198                    if (item.accessTokenId === '' || item.permission === '') {
199                      return;
200                    }
201                    let _this = this;
202                    if (isOn) {
203                      let promises = routerData.map(it => new Promise((resolve) => {
204                        _this.grantUserGrantedPermission(item.accessTokenId, it.permission, item.index, resolve);
205                      }));
206                      Promise.all(promises).then(function() {
207                        _this.toggleIsOn[item.index] = true;
208                        let num = Constants.PERMISSION_NUM;
209                        for(let key in _this.toggleIsOn){
210                          if(_this.toggleIsOn[key]){
211                            num++;
212                          }
213                        }
214                        _this.permissionNum = num;
215                      });
216                    } else {
217                      let promises = routerData.map(it => new Promise((resolve) => {
218                        _this.revokeUserGrantedPermission(item.accessTokenId, it.permission, item.index, resolve);
219                      }));
220                      Promise.all(promises).then(function() {
221                        _this.toggleIsOn[item.index] = false;
222                        let num = Constants.PERMISSION_NUM;
223                        for(let key in _this.toggleIsOn){
224                          if(_this.toggleIsOn[key]){
225                            num++;
226                          }
227                        }
228                        _this.permissionNum = num;
229                      });
230                    }
231                  })
232              }else {
233                Text(this.polymorphismIsOn[item.index] ? $r('app.string.allow') : $r('app.string.ban'))
234                .fontSize(Constants.TEXT_SMAL_FONT_SIZE)
235                .fontColor($r('app.color.label_color_light'))
236                .margin({ right: Constants.AUTHORITY_IMAGE_MARGIN_RIGHT })
237                Image($r('app.media.ic_public_arrow_right'))
238                  .customizeImage(Constants.IMAGE_WIDTH, Constants.IMAGE_HEIGHT)
239              }
240            }
241            .width(Constants.FULL_WIDTH)
242            .height(Constants.AUTHORITY_ROW_HEIGHT)
243            .constraintSize({ minHeight: Constants.AUTHORITY_CONSTRAINTSIZE_MINHEIGHT })
244          }
245          if (!index) {
246            Row() {
247              Flex() {
248                Column().width(Constants.APPLICATION_TEXT_DECORATION_MARGIN_LEFT)
249                Column()
250                  .backgroundColor($r('app.color.text_decoration_color'))
251                  .height(Constants.TEXT_DECORATION_HEIGHT)
252                  .flexGrow(Constants.FLEX_GROW)
253              }
254            }
255          }
256        }.onClick(() => {
257          if (polymorphismGroup.indexOf(globalThis.currentPermissionGroup) !== -1) {
258            var permissions: any = []
259            routerData.forEach(item => {
260              permissions.push(item.permission)
261            })
262            router.pushUrl({
263              url: 'pages/application-tertiary',
264              params: {
265                routerData: this.bundleNameGroup[item.index],
266                backTitle,
267                permission: permissions,
268                status: this.polymorphismIsOn[item.index] ? Constants.RADIO_ALLOW_INDEX : Constants.RADIO_BAN_INDEX
269              }
270            });
271          }
272        })
273      }
274    }.padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
275  }
276
277  /**
278   * Take the total number of access applications
279   */
280  getGrantApplicationNumber() {
281    if (polymorphismGroup.indexOf(globalThis.currentPermissionGroup) !== -1) {
282      var sum = this.polymorphismIsOn.filter(item => item == true)
283      return sum.length
284    }else {
285      return this.permissionNum
286    }
287  }
288
289  /**
290   * Grant permissions to the app
291   * @param {Number} accessTokenId
292   * @param {String} permission permission name
293   * @param {Number} index Array index to modify permission status
294   */
295  grantUserGrantedPermission(accessTokenId, permission, index, resolve) {
296    abilityAccessCtrl.createAtManager().grantUserGrantedPermission(
297      accessTokenId, permission, Constants.PERMISSION_FLAG).then(result => {
298      // result: 0 Authorization succeeded; result: -1 Authorization failed
299      resolve(result);
300    }).catch(error => {
301      resolve(-1);
302      console.error(TAG + 'abilityAccessCtrl.createAtManager.grantUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
303    })
304  }
305
306  /**
307   * Deauthorize the app
308   * @param {Number} accessTokenId
309   * @param {String} permission permission name
310   * @param {Number} index Array index to modify permission status
311   */
312  revokeUserGrantedPermission(accessTokenId, permission, index, resolve) {
313    abilityAccessCtrl.createAtManager().revokeUserGrantedPermission(
314      accessTokenId, permission, Constants.PERMISSION_FLAG).then(result => {
315      // result: 0 successfully cancel the authorization; result: -1 cancel the authorization failed
316      resolve(result);
317    }).catch(error => {
318      resolve(-1);
319      console.error(TAG + 'abilityAccessCtrl.createAtManager.revokeUserGrantedPermission failed. Cause: ' + JSON.stringify(error));
320    })
321  }
322
323  /**
324   * Lifecycle function, executed when the page is initialized
325   */
326  aboutToAppear() {
327    var bundleNames = []
328    this.applicationList = []
329    routerData.forEach(permissionmanager => {
330      permissionmanager.bundleNames.forEach( bundleName => {
331        if (bundleNames.indexOf(bundleName) == -1) {
332          bundleNames.push(bundleName)
333        }
334      })
335    })
336
337    globalThis.context.resourceManager.getString($r("app.string.textInput_placeholder").id).then(val => {
338      this.placeholder = val
339    })
340
341    // initial then fill values when sync return which may cause sync panic
342    for (let i = 0; i < bundleNames.length; i++) {
343      this.applicationList.push(new ApplicationObj('', '', i, 0, '', ''));
344      this.bundleNameGroup.push(bundleNames[i])
345    }
346
347    for (let i = 0; i < bundleNames.length; i++) {
348      // Get BundleInfo based on bundle name
349      bundle.getBundleInfo(bundleNames[i], Constants.PARMETER_BUNDLE_FLAG).then(res => {
350        Promise.all([getAppLabel(res.appInfo.labelId, res.name),
351        getAppIcon(res.appInfo.iconId, res.name)
352        ])
353          .then((values) => {
354            this.applicationList[i] = (
355              new ApplicationObj(
356              String(values[0]),
357              String(values[1]),
358                i,
359                res.appInfo.accessTokenId,
360                routerData[0].permission,
361              makePy(values[0])[0].slice(0, 1)) // Get the first letter in the returned initials array
362            );
363            this.bundleNameGroup[i] = bundleNames[i]
364          });
365        // 0: have permission; -1: no permission
366        var boole = true;
367        this.permissionNum++;
368        for (let j = 0; j < routerData.length; j++) {
369          if (res.reqPermissions.indexOf(routerData[j].permission) == -1) {
370            continue
371          }
372          verifyAccessToken(res.appInfo.accessTokenId, routerData[j].permission).then((access) => {
373            if (Number(access) === Constants.PERMISSION_INDEX) {
374              if(boole){
375                this.toggleIsOn[i] = true;
376              }
377            } else {
378              if(boole){
379                this.permissionNum--
380              }
381              boole = false;
382              this.toggleIsOn[i] = false;
383            }
384          });
385        }
386      }).catch(error => {
387        console.log(TAG + bundleNames[i] + "getBundleInfo failed, cause: " + JSON.stringify(error));
388      })
389    }
390    if(globalGroup.indexOf(globalThis.currentPermissionGroup) !== -1) {
391      this.globalIsOn = globalIsOn
392    }
393  }
394
395  build() {
396    Column() {
397      Row() {
398        textInput({
399          placeholder: this.placeholder,
400          applicationItem: $applicationList,
401          searchResult: $searchResult
402        })
403      }.padding({
404        left: Constants.AUTHORITY_TEXTINPUT_PADDING_LEFT,
405        right: Constants.AUTHORITY_TEXTINPUT_PADDING_RIGHT
406      })
407      Flex({ alignItems:ItemAlign.Start, justifyContent: FlexAlign.Start }) {
408        Column() {
409          if(globalGroup.indexOf(globalThis.currentPermissionGroup) !== -1) {
410            Row() {
411              Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
412                Text(globalThis.currentPermissionGroup == "CAMERA" ? $r('app.string.camera') : $r('app.string.microphone'))
413                  .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE).fontColor($r('app.color.label_color'))
414                  .fontWeight(FontWeight.Medium)
415                Row() {
416                  Toggle({ type: ToggleType.Switch, isOn: this.globalIsOn })
417                    .selectedColor($r('app.color.button_color'))
418                    .switchPointColor($r('app.color.selected_Color'))
419                    .padding({ right: 0 })
420                    .onChange((isOn: boolean) => {
421                      if(isOn) {
422                        if(globalThis.currentPermissionGroup == "CAMERA") {
423                          let cameraManager = camera.getCameraManager(globalThis.context);
424                          cameraManager.muteCamera(false);
425                          this.globalIsOn = isOn;
426                        }else {
427                          var audioManager = audio.getAudioManager();
428                          audioManager.setMicrophoneMute(false).then(() => {
429                            this.globalIsOn = isOn
430                          })
431                        }
432                      }
433                    })
434                  Row().onClick(() => { this.privacyDialogController.open() })
435                    .width(Constants.DEFAULT_SLIDER_WIDTH).height(Constants.DEFAULT_SLIDER_HEIGHT)
436                    .position({ x: this.globalIsOn ? 0 : Constants.OFFSET, y: 0 })
437                }.clip(true)
438              }.height(Constants.LISTITEM_ROW_HEIGHT)
439              .padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
440            }.padding({ top: Constants.LIST_PADDING_TOP, bottom: Constants.LIST_PADDING_BOTTOM })
441            .backgroundColor($r('app.color.default_background_color'))
442            .borderRadius(Constants.BORDER_RADIUS)
443            .margin({ top: Constants.TERTIARY_ROW_MARGIN_TOP })
444          }
445          Flex({ justifyContent: FlexAlign.Start }) {
446            if(this.globalIsOn) {
447              Text(String(this.getGrantApplicationNumber()))
448                .fontSize(Constants.TEXT_SMAL_FONT_SIZE)
449                .fontColor($r('app.color.secondary_font_color'))
450                .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP, left: Constants.AUTHORITY_TEXT_MARGIN_LEFT })
451              Text($r('app.string.number_of_authorized_applications'))
452                .fontSize(Constants.TEXT_SMAL_FONT_SIZE)
453                .fontColor($r('app.color.secondary_font_color'))
454                .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP, left: Constants.AUTHORITY_TEXT_MARGIN_LEFT })
455            }else {
456              Text(globalThis.currentPermissionGroup == "CAMERA" ? $r('app.string.camera_is_off') : $r('app.string.microphone_is_off'))
457                .fontSize(Constants.TEXT_SMAL_FONT_SIZE)
458                .fontColor($r('app.color.secondary_font_color'))
459                .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP, left: Constants.AUTHORITY_TEXT_MARGIN_LEFT })
460            }
461          }.padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END })
462          .margin({ bottom: Constants.AUTHORITY_ROW_MARGIN_BOTTOM })
463          Scroll() {
464            Row() {
465              Column() {
466                if (!this.applicationList.length) {
467                  if (this.searchResult) {
468                    Row() {}
469                  } else {
470                    Row() {
471                      Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
472                        Image($r('app.media.searchnoresult'))
473                          .customizeImage(Constants.SEARCHNORESULT_IMAGE_WIDTH, Constants.SEARCHNORESULT_IMAGE_HEIGHT)
474                      }
475                    }
476                  }
477                } else {
478                  Row() {
479                    List() {
480                      ForEach(this.applicationList.slice(Constants.SLICE_START, this.applicationList.length - 1),
481                      (item) => {
482                        this.ListItemLayout(item, Constants.SLICE_START_INDEX)
483                      }, item => item.toString())
484                      ForEach(this.applicationList.slice(Constants.SLICE_END), (item) => {
485                        this.ListItemLayout(item, Constants.SLICE_END_INDEX)
486                      }, item => item.toString())
487                    }
488                    .backgroundColor($r('app.color.default_background_color'))
489                    .borderRadius(Constants.BORDER_RADIUS)
490                    .padding({ top: Constants.LIST_PADDING_TOP, bottom: Constants.LIST_PADDING_BOTTOM })
491                  }
492                }
493              }.width(Constants.FULL_WIDTH)
494              .margin({ bottom: globalGroup.includes(globalThis.currentPermissionGroup) ? Constants.AUTHORITY_LIST_MARGIN_BOTTOM_GLOBAL : Constants.AUTHORITY_LIST_MARGIN_BOTTOM })
495            }
496          }.scrollBar(BarState.Off)
497          .borderRadius(Constants.BORDER_RADIUS)
498        }.padding({ left: Constants.AUTHORITY_LISTITEM_PADDING_LEFT })
499        Column() {
500          alphabetIndexerComponent({ applicationItem: $applicationList })
501        }.width(Constants.AUTHORITY_ALPHABETINDEX_WIDTH)
502         .padding({ top: Constants.AUTHORITY_ALPHABETINDEX_PADDING_TOP })
503      }.flexGrow(Constants.FLEX_GROW)
504    }.height(Constants.FULL_HEIGHT)
505  }
506}
507