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