• 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 abilityAccessCtrl from '@ohos.abilityAccessCtrl';
17import bundle from '@ohos.bundle';
18import bundleManager from '@ohos.bundle.bundleManager';
19import rpc from '@ohos.rpc';
20import { Log, getPermissionGroup } from '../common/utils/utils'
21import Constants from '../common/utils/constant'
22import { BundleFlag } from '../common/model/bundle'
23import { permissionGroups, showSubpermissionsGrop } from '../common/model/permissionGroup'
24import { LocationCanvas } from '../common/components/location'
25
26@Extend(Button) function customizeButton() {
27  .backgroundColor($r('app.color.default_background_color'))
28  .fontColor($r('app.color.button_color'))
29  .fontWeight(FontWeight.Medium)
30  .height(Constants.BUTTON_HEIGHT)
31  .width(Constants.BUTTON_WIDTH)
32}
33
34const FUZZY_LOCATION_PERMISSION = 'ohos.permission.APPROXIMATELY_LOCATION'
35const PRECISE_LOCATION_PERMISSION = 'ohos.permission.LOCATION'
36
37let permissionLabels: Object = {}
38let win: any = ""
39let proxy: any = ''
40
41class ResourceObj {
42  whether_to_allow: string
43  quotes: string
44  access_general_location: string
45  fuzzy_to_exact: string
46  comma: string
47  period: string
48  constructor(whether_to_allow: string, quotes: string, access_general_location: string, fuzzy_to_exact: string, comma: string, period: string) {
49    this.whether_to_allow = whether_to_allow
50    this.quotes = quotes
51    this.access_general_location = access_general_location
52    this.fuzzy_to_exact = fuzzy_to_exact
53    this.comma = comma
54    this.period = period
55  }
56}
57
58class BundleInfo {
59  targetVersion: number
60  reqPermissionDetails: Array<any>
61  constructor(targetVersion: number, reqPermissionDetails: Array<any>) {
62    this.targetVersion = targetVersion
63    this.reqPermissionDetails = reqPermissionDetails
64  }
65}
66
67@Entry
68@Component
69struct dialogPlusPage {
70  privacyDialogController: CustomDialogController = new CustomDialogController({
71    builder: PermissionDialog(),
72    autoCancel: false,
73    alignment: DialogAlignment.Center,
74    customStyle: true
75  })
76
77  build() {}
78
79  aboutToAppear() {
80    this.privacyDialogController.open()
81  }
82}
83
84@CustomDialog
85struct PermissionDialog {
86  @State count: number = 0
87  @State result: Array<any> = []
88  @State accessTokenId: number = 0
89  @State initStatus: number = Constants.INIT_NEED_TO_WAIT
90  @State reqPerms: Array<string> = []
91  @State grantGroups: Array<any> = []
92  @State userFixedFlag: number = 2 // means user fixed
93  @State appName: string = ""
94  @State locationFlag: number = Constants.LOCATION_NONE
95  @State resource: ResourceObj = new ResourceObj('', '', '', '', '', '')
96  @State bundleInfo: BundleInfo = new BundleInfo(0, [])
97  controller: CustomDialogController
98
99  build() {
100    GridRow({ columns: { xs: Constants.XS_COLUMNS, sm: Constants.SM_COLUMNS, md: Constants.MD_COLUMNS, lg: Constants.LG_COLUMNS }, gutter: Constants.DIALOG_GUTTER }) {
101      GridCol({ span: { xs: Constants.XS_SPAN, sm: Constants.SM_SPAN, md: Constants.DIALOG_MD_SPAN, lg: Constants.DIALOG_LG_SPAN },
102        offset: {xs: Constants.XS_OFFSET, sm: Constants.SM_OFFSET, md: Constants.DIALOG_MD_OFFSET, lg: Constants.DIALOG_LG_OFFSET} }) {
103        Flex({ justifyContent: FlexAlign.Center, alignItems: globalThis.isBottomPopover ? ItemAlign.End : ItemAlign.Center }) {
104          Column() {
105            if ((this.initStatus != Constants.INIT_NEED_TO_WAIT) && this.verify()) {
106              Image(this.grantGroups[this.count].icon)
107                .width(Constants.DIALOG_ICON_WIDTH)
108                .height(Constants.DIALOG_ICON_HEIGHT)
109                .fillColor($r("app.color.first_font_color"))
110                .margin({
111                  top: Constants.DIALOG_ICON_MARGIN_TOP
112                })
113              if(this.grantGroups.length > 1) {
114                Text(`${this.count + 1} / ${this.grantGroups.length}`)
115                  .fontSize(Constants.DIALOG_LABEL_FONT_SIZE)
116                  .fontColor($r('app.color.text_secondary_color'))
117                  .lineHeight(Constants.DIALOG_LABEL_LINE_HEIGHT)
118                  .margin({
119                    top: Constants.DIALOG_LABEL_MARGIN_TOP
120                  })
121              }
122              Column() {
123                Row() {
124                  Flex({ justifyContent: FlexAlign.Start }) {
125                    Text(this.showTitle())
126                      .fontSize(Constants.DIALOG_REQ_FONT_SIZE)
127                      .fontColor($r('app.color.first_font_color'))
128                      .fontWeight(FontWeight.Medium)
129                      .fontSize(Constants.DIALOG_REQ_FONT_SIZE)
130                      .lineHeight(Constants.DIALOG_REQ_LINE_HEIGHT)
131                      .margin({
132                        top: Constants.DIALOG_REQ_MARGIN_TOP,
133                        left: Constants.DIALOG_REQ_MARGIN_LEFT,
134                        right: Constants.DIALOG_REQ_MARGIN_RIGHT
135                      })
136                  }
137                }
138
139                Row() {
140                  Flex({ justifyContent: FlexAlign.Start }) {
141                    Text(this.showReason())
142                      .fontSize(Constants.DIALOG_DESP_FONT_SIZE)
143                      .fontColor($r('app.color.text_secondary_color'))
144                      .fontSize(Constants.DIALOG_DESP_FONT_SIZE)
145                      .lineHeight(Constants.DIALOG_DESP_LINE_HEIGHT)
146                      .margin({
147                        top: Constants.DIALOG_DESP_MARGIN_TOP,
148                        left: Constants.DIALOG_DESP_MARGIN_LEFT,
149                        right: Constants.DIALOG_DESP_MARGIN_RIGHT,
150                        bottom: Constants.DIALOG_DESP_MARGIN_BOTTOM
151                      })
152                  }
153                }
154
155                if(this.locationFlag > Constants.LOCATION_NONE) {
156                  LocationCanvas({ locationFlag: $locationFlag })
157                }
158              }
159            }
160            Row() {
161              Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
162                Button($r('app.string.ban'))
163                  .fontSize(Constants.BUTTON_FONT_SIZE)
164                  .onClick(() => {
165                    this.privacyCancel(this.grantGroups[this.count], this.accessTokenId, this.reqPerms, this.userFixedFlag)
166                  }).customizeButton().margin({ left: Constants.BUTTON_MARGIN_LEFT })
167                Text('|').fontSize(Constants.BUTTON_DIVIDER_FONT_SIZE).fontColor($r('app.color.divider_color'))
168                Button($r('app.string.allow'))
169                  .fontSize(Constants.BUTTON_FONT_SIZE)
170                  .onClick(() => {
171                    this.privacyAccept(this.grantGroups[this.count], this.accessTokenId, this.reqPerms, this.userFixedFlag)
172                  }).customizeButton().margin({ right: Constants.BUTTON_MARGIN_RIGHT })
173              }
174            }
175          }
176          .backgroundColor($r('app.color.default_background_color'))
177          .borderRadius(Constants.DIALOG_PRIVACY_BORDER_RADIUS)
178          .width(Constants.FULL_WIDTH)
179          .padding({ bottom: Constants.DIALOG_PADDING_BOTTOM })
180          .margin({ bottom: Constants.PERMISSION_DIALOG_MARGIN_BOTTOM })
181        }.width(Constants.FULL_WIDTH)
182        .height(Constants.FULL_HEIGHT)
183      }
184    }.margin({ left: globalThis.isBottomPopover ? Constants.DIALOG_MARGIN_VERTICAL : Constants.DIALOG_MARGIN,
185      right: globalThis.isBottomPopover ? Constants.DIALOG_MARGIN_VERTICAL : Constants.DIALOG_MARGIN })
186  }
187
188  showTitle() {
189    if(this.grantGroups[this.count].name == 'LOCATION') {
190      if(this.locationFlag == Constants.LOCATION_FUZZY) {
191        return this.resource.whether_to_allow + this.appName + this.resource.access_general_location
192      }
193      if(this.locationFlag == Constants.LOCATION_UPGRADE) {
194        return this.resource.whether_to_allow + this.appName + this.resource.fuzzy_to_exact
195      }
196    }
197    return this.resource.whether_to_allow + this.appName + this.resource.quotes + this.grantGroups[this.count].label
198  }
199
200  showReason() {
201    if(this.grantGroups[this.count].name == 'LOCATION') {
202      if((this.locationFlag == Constants.LOCATION_FUZZY) || (this.locationFlag == Constants.LOCATION_BOTH_FUZZY)) {
203        return $r('app.string.close_exact_position')
204      }
205    }
206    return this.grantGroups[this.count].description
207  }
208
209  verify() {
210    if((this.initStatus == Constants.INIT_NEED_TO_TERMINATED) || (this.count >= this.grantGroups.length)) {
211      this.answerRequest()
212      this.initStatus = Constants.INIT_NEED_TO_WAIT
213      return false
214    }
215    return true
216  }
217
218  answerRequest() {
219    var ret: number = Constants.RESULT_SUCCESS
220    if (this.initStatus == Constants.INIT_NEED_TO_TERMINATED) {
221      ret = Constants.RESULT_FAILURE
222    }
223    this.answer(ret, this.reqPerms)
224  }
225
226  answer(ret, reqPerms) {
227    Log.info("code:" + ret + ", perms="+ JSON.stringify(reqPerms) +", result=" + JSON.stringify(this.result))
228    var perms = []
229    var results = []
230    reqPerms.forEach(perm => {
231      perms.push(perm)
232    })
233    this.result.forEach(result => {
234      results.push(result)
235    })
236    let option = new rpc.MessageOption()
237    let data = new rpc.MessageSequence()
238    let reply = new rpc.MessageSequence()
239    Promise.all([data.writeInterfaceToken(Constants.ACCESS_TOKEN),
240      data.writeStringArray(perms),
241      data.writeIntArray(results)
242    ]).then(() => {
243      proxy.sendRequest(Constants.RESULT_CODE, data, reply, option)
244      this.destruction()
245    }).catch(() => {
246      Log.error('write result failed!')
247      this.destruction()
248    })
249  }
250
251  destruction() {
252    win.destroy()
253    globalThis.windowNum --
254    Log.info("windowNum:" + globalThis.windowNum)
255    if(globalThis.windowNum == 0) {
256      globalThis.extensionContext.terminateSelf()
257    }
258  }
259
260  async privacyAccept(group, accessTokenId, permissionList, userFixedFlag) {
261    var acManager = abilityAccessCtrl.createAtManager()
262    var num = 0
263    group.permissions.forEach(async permission => {
264      let result
265      if(showSubpermissionsGrop.indexOf(group.name) == -1) {
266        if(group.name == 'LOCATION' && this.bundleInfo.targetVersion >= Constants.API_VERSION_SUPPORT_STAGE) {
267          if(!(((this.locationFlag == Constants.LOCATION_BOTH_FUZZY) || (this.locationFlag == Constants.LOCATION_FUZZY))
268            && (permission == PRECISE_LOCATION_PERMISSION))) {
269            await acManager.grantUserGrantedPermission(accessTokenId, permission, userFixedFlag).then(() => {
270              result = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
271            })
272          }
273        }else {
274          await acManager.grantUserGrantedPermission(accessTokenId, permission, userFixedFlag).then(() => {
275            result = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
276          })
277        }
278      }else {
279        if(permissionList.includes(permission)) {
280          await acManager.grantUserGrantedPermission(accessTokenId, permission, userFixedFlag).then(() => {
281            result = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
282          })
283        }
284      }
285      num ++
286      Log.info("grant permission result:" + result + "permission" + permission)
287      if (result == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
288        permissionList.forEach((req, idx) => {
289          if(req == permission) {
290            this.result[idx] = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
291          }
292        })
293        Log.info("grant permission success:" + permission)
294      } else {
295        Log.error("failed to grant permission:" + permission + " ret:" + result)
296      }
297      if(num == group.permissions.length) {
298        this.count ++
299      }
300    })
301  }
302
303  async privacyCancel(group, accessTokenId, permissionList, userFixedFlag) {
304    var acManager = abilityAccessCtrl.createAtManager()
305    group.permissions.forEach(async permission => {
306      if(showSubpermissionsGrop.indexOf(group.name) == -1) {
307        if(!(this.locationFlag == Constants.LOCATION_UPGRADE && group.name == 'LOCATION') || permission == PRECISE_LOCATION_PERMISSION) {
308          await acManager.revokeUserGrantedPermission(accessTokenId, permission, userFixedFlag)
309        }
310      }else {
311        if(permissionList.includes(permission)) {
312          await acManager.revokeUserGrantedPermission(accessTokenId, permission, userFixedFlag)
313        }
314      }
315      Log.info("revoke permission " + permission);
316    })
317    this.count ++
318  }
319
320  getgrantGroups(stateGroup) {
321    //Processing of positioning
322    if(this.bundleInfo.targetVersion >= Constants.API_VERSION_SUPPORT_STAGE) {
323      if(this.reqPerms.includes(FUZZY_LOCATION_PERMISSION)) {
324        this.locationFlag = Constants.LOCATION_FUZZY
325        if(this.reqPerms.includes(PRECISE_LOCATION_PERMISSION)) {
326          this.locationFlag = Constants.LOCATION_BOTH_PRECISE
327          var fuzzyIndex = this.reqPerms.indexOf(FUZZY_LOCATION_PERMISSION)
328          if(stateGroup[fuzzyIndex] == Constants.PASS_OPER) {
329            this.locationFlag = Constants.LOCATION_UPGRADE
330          }
331        }
332      }
333    }
334
335    this.reqPerms.forEach((permission, idx) => {
336      //已授权
337      if(stateGroup[idx] == Constants.PASS_OPER) {
338        Log.info("permission has been fixed:" + permission)
339        this.result[idx] = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
340        //待授权
341      }else if(stateGroup[idx] == Constants.DYNAMIC_OPER) {
342        var group = getPermissionGroup(permission)
343        if(!group) {
344          Log.info("permission not find:" + permission)
345        }else {
346          var exist = this.grantGroups.find(grantGroup => grantGroup.name == group.name)
347          //判断是否为需要展示子权限的权限组
348          if(showSubpermissionsGrop.indexOf(group.name) != -1) {
349            if(!exist) {
350              group.description = [permissionLabels[permission]]
351              this.grantGroups.push(group)
352            }else {
353              if(exist.description.indexOf(permissionLabels[permission]) == -1) {
354                exist.description.push(permissionLabels[permission])
355              }
356            }
357          }else {
358            if(!exist) {
359              this.grantGroups.push(group)
360            }
361          }
362        }
363      }
364    })
365    this.initStatus = Constants.INIT_NEED_TO_VERIFY
366  }
367
368  getApplicationName(bundleName, uid) {
369    Log.info("getApplicationName bundleName:" + bundleName)
370    Log.info("getApplicationName userId:" + Math.floor(uid/200000))
371    bundle.getApplicationInfo(bundleName, BundleFlag.GET_BUNDLE_DEFAULT, Math.floor(uid/200000)).then(applicationInfo => {
372      let context = globalThis.extensionContext.createBundleContext(bundleName)
373      context.resourceManager.getString(applicationInfo.labelId, (err, value) => {
374        if (value == undefined) {
375          this.appName = applicationInfo.label
376        } else {
377          this.appName = value
378        }
379        Log.info("hap label:" + applicationInfo.label + ", value:"+this.appName)
380      })
381    }).catch(err => {
382      Log.error("applicationInfo error :" + err)
383      this.initStatus = Constants.INIT_NEED_TO_TERMINATED
384    })
385    bundleManager.getBundleInfo(bundleName, Constants.PARMETER_BUNDLE_FLAG).then(info => {
386      this.grantGroups.forEach((group) => {
387        globalThis.extensionContext.resourceManager.getString(group.label.id, (err, val) => {
388          group.label = val
389        })
390        if(group.description) {
391          Promise.all([globalThis.extensionContext.resourceManager.getString($r("app.string.separator").id),
392          globalThis.extensionContext.resourceManager.getString($r("app.string.reason_suffix").id),
393          globalThis.extensionContext.resourceManager.getString($r("app.string.and").id),
394          globalThis.extensionContext.resourceManager.getString($r("app.string.period").id)])
395            .then(values => {
396              group.description = group.name == 'SMS' ? (group.description.join(values[0]) + values[1]) : (group.description.join(values[2]) + values[3])
397              this.getReason(group, info, bundleName)
398            })
399        }else {
400          this.getReason(group, info, bundleName)
401        }
402      })
403    })
404  }
405
406  getReason(group, bundleInfo, bundleName) {
407    group.permissions.forEach(permission => {
408      if(this.reqPerms.indexOf(permission) != -1) {
409        bundleInfo.reqPermissionDetails.forEach(reqPermissionDetail => {
410          if(reqPermissionDetail.name == permission) {
411            let context = globalThis.extensionContext.createBundleContext(bundleName)
412            context.resourceManager.getString(reqPermissionDetail.reasonId, (err, value) => {
413              this.initStatus = Constants.INIT_NEED_TO_REFRESH
414              if (value !== undefined && !group.hasReason) {
415                group.description = group.description.replace(this.resource.period, this.resource.comma)
416                group.description += value.slice(Constants.START_SUBSCRIPT, Constants.END_SUBSCRIPT)
417                group.hasReason = true
418              }
419            })
420          }
421        })
422      }
423    })
424  }
425
426  getStrings() {
427    globalThis.extensionContext.resourceManager.getString($r("app.string.whether_to_allow").id, (err, val) => {
428      this.resource.whether_to_allow = val
429    })
430    globalThis.extensionContext.resourceManager.getString($r("app.string.quotes").id, (err, val) => {
431      this.resource.quotes = val
432    })
433    globalThis.extensionContext.resourceManager.getString($r("app.string.access_general_location").id, (err, val) => {
434      this.resource.access_general_location = val
435    })
436    globalThis.extensionContext.resourceManager.getString($r("app.string.fuzzy_to_exact").id, (err, val) => {
437      this.resource.fuzzy_to_exact = val
438    })
439    globalThis.extensionContext.resourceManager.getString($r("app.string.comma").id, (err, val) => {
440      this.resource.comma = val
441    })
442    globalThis.extensionContext.resourceManager.getString($r("app.string.period").id, (err, val) => {
443      this.resource.period = val
444    })
445    this.reqPerms.forEach(reqPerm => {
446      permissionGroups.forEach(permissionInfo => {
447        if(reqPerm == permissionInfo.permissionName) {
448          globalThis.extensionContext.resourceManager.getString(permissionInfo.label.id).then(val => {
449            permissionLabels[reqPerm] = val
450          })
451        }
452      })
453    })
454  }
455
456  aboutToAppear() {
457    this.count = 0;
458    this.initStatus = Constants.INIT_NEED_TO_WAIT
459    this.result = []
460    this.reqPerms = globalThis.abilityWant.parameters['ohos.user.grant.permission']
461    this.accessTokenId = globalThis.abilityWant.parameters['ohos.aafwk.param.callerToken']
462    proxy = globalThis.abilityWant.parameters['ohos.ability.params.callback'].value
463    win = globalThis.extensionWin
464    if (this.reqPerms == undefined || this.accessTokenId == undefined || this.reqPerms.length == 0) {
465      Log.info("invalid parameters")
466      this.initStatus = Constants.INIT_NEED_TO_TERMINATED
467      return
468    }
469    Log.info("request permission=" + JSON.stringify(this.reqPerms) + ", tokenId = " + this.accessTokenId)
470    Log.info("permission state=" + JSON.stringify(globalThis.abilityWant.parameters['ohos.user.grant.permission.state']));
471    this.result = new Array(this.reqPerms.length).fill(-1);
472    this.getStrings()
473    let uid = globalThis.abilityWant.parameters['ohos.aafwk.param.callerUid']
474    bundle.getNameForUid(uid).then((data) => {
475      bundle.getBundleInfo(data, Constants.PARMETER_BUNDLE_FLAG).then(bundleInfo => {
476        this.bundleInfo = bundleInfo
477        this.getgrantGroups(globalThis.abilityWant.parameters['ohos.user.grant.permission.state']);
478        this.getApplicationName(data, uid)
479      })
480    }).catch(err => {
481      Log.error("getNameForUid error :" + JSON.stringify(err))
482      this.initStatus = Constants.INIT_NEED_TO_TERMINATED
483    })
484  }
485}
486
487