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