1/* 2 * Copyright (c) 2021-2023 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 router from '@ohos.router'; 18import common from '@ohos.app.ability.common'; 19import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; 20import bundleManager from '@ohos.bundle.bundleManager'; 21import { BusinessError } from '@ohos.base'; 22import { groups } from '../common/model/permissionGroup'; 23import Constants from '../common/utils/constant'; 24import { Log, verifyAccessToken, getGroupIdByPermission, supportPermission } from '../common/utils/utils'; 25import { PermissionObj, AppInfo } from '../common/model/typedef'; 26import { GlobalContext } from '../common/utils/globalContext'; 27import { Permission } from '../common/model/definition'; 28 29@Entry 30@Component 31struct appNamePlusPage { 32 private context = getContext(this) as common.UIAbilityContext; 33 @State allowedListItem: PermissionObj[] = []; // Array of allowed permissions 34 @State bannedListItem: PermissionObj[] = []; // array of forbidden permissions 35 @State applicationInfo: AppInfo = GlobalContext.load('applicationInfo'); // Routing jump data 36 @State bundleName: string = GlobalContext.load('bundleName'); 37 @State label: string = ''; 38 @State isTouch: string = ''; 39 @State isGranted: number = Constants.PERMISSION_ALLOW; 40 @State folderStatus: boolean[] = [false, false, false]; 41 @State reqUserPermissions: Permission[] = []; 42 43 @Builder ListItemLayout(item: PermissionObj, status: number) { 44 ListItem() { 45 Row() { 46 Column() { 47 Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 48 Row() { 49 Text(item.groupName) 50 .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE) 51 .fontColor($r('sys.color.font_primary')) 52 .fontWeight(FontWeight.Medium) 53 .flexGrow(Constants.FLEX_GROW) 54 SymbolGlyph($r('sys.symbol.chevron_forward')) 55 .width(Constants.IMAGE_WIDTH) 56 .height(Constants.IMAGE_HEIGHT) 57 .fontSize(Constants.FONT_SIZE_18_vp) 58 .fontColor([$r('sys.color.icon_tertiary')]) 59 .fontWeight(FontWeight.Medium) 60 } 61 .width(Constants.FULL_WIDTH) 62 .height(Constants.LISTITEM_ROW_HEIGHT) 63 } 64 }.onClick(() => { 65 GlobalContext.store('currentPermissionGroup', item.group); 66 router.pushUrl({ 67 url: item.group == 'OTHER' ? 'pages/other-permissions' : 'pages/application-tertiary', 68 params: { 69 bundleName: this.applicationInfo.bundleName, 70 backTitle: item.groupName, 71 permission: item.permission, 72 status, 73 tokenId: this.applicationInfo.tokenId 74 } 75 }); 76 }) 77 } 78 }.padding({ left: $r('sys.float.ohos_id_card_margin_start'), right: $r('sys.float.ohos_id_card_margin_end') }) 79 .borderRadius($r('sys.float.ohos_id_corner_radius_default_l')) 80 .linearGradient((this.isTouch === item.group) ? { 81 angle: 90, 82 direction: GradientDirection.Right, 83 colors: [['#DCEAF9', 0.0], ['#FAFAFA', 1.0]] 84 } : { 85 angle: 90, 86 direction: GradientDirection.Right, 87 colors: [[$r('sys.color.comp_background_list_card'), 1], [$r('sys.color.comp_background_list_card'), 1]] 88 }) 89 .onTouch(event => { 90 if (event === undefined) { 91 return; 92 } 93 if (event.type === TouchType.Down) { 94 this.isTouch = item.group; 95 } 96 if (event.type === TouchType.Up) { 97 this.isTouch = ''; 98 } 99 }) 100 } 101 102 async getReqUserPermissions(info: AppInfo) { 103 let acManager = abilityAccessCtrl.createAtManager(); 104 if (info.permissions.length > 0) { 105 for (let j = 0; j < info.permissions.length; j++) { 106 let permission = info.permissions[j] as Permission; 107 let supportPermissions = supportPermission(); 108 if (supportPermissions.indexOf(permission) == -1) { 109 continue; 110 } 111 try { 112 let flag = await acManager.getPermissionFlags(info.tokenId, permission); 113 if (flag == Constants.PERMISSION_SYSTEM_FIXED) { 114 continue; 115 } 116 } catch (err) { 117 Log.error('getPermissionFlags error: ' + JSON.stringify(err)); 118 } 119 this.reqUserPermissions.push(permission); 120 } 121 } 122 } 123 124 async initApplicationInfo(info: AppInfo) { 125 Log.info(`labelResource: ` + JSON.stringify(info.labelResource)); 126 let resourceManager = this.context.createBundleContext(info.bundleName).resourceManager; 127 128 if (info.labelResource.id !== 0) { 129 info.label = await this.context.resourceManager.getStringValue(info.labelResource); 130 } else { 131 info.label = await resourceManager.getStringValue(info.labelId); 132 } 133 134 try { 135 if (info.iconResource.id !== 0) { 136 let iconDescriptor = this.context.resourceManager.getDrawableDescriptor(info.iconResource); 137 info.icon = iconDescriptor?.getPixelMap(); 138 } else { 139 let iconDescriptor = resourceManager.getDrawableDescriptor(info.iconId); 140 info.icon = iconDescriptor?.getPixelMap(); 141 } 142 } catch (error) { 143 Log.error(`getDrawableDescriptor failed, error code: ${error.code}, message: ${error.message}.`); 144 } 145 146 if (!info.icon) { 147 info.icon = $r('app.media.icon'); 148 } 149 150 this.reqUserPermissions = []; 151 await this.getReqUserPermissions(info); 152 let groupIds: number[] = []; 153 for (let i = 0; i < this.reqUserPermissions.length; i++) { 154 let groupId = getGroupIdByPermission(this.reqUserPermissions[i]) 155 if (groupIds.indexOf(groupId) == -1) { 156 groupIds.push(groupId); 157 } 158 } 159 info.permissions = this.reqUserPermissions; 160 info.groupId = groupIds; 161 } 162 163 /** 164 * Initialize permission status information and group permission information 165 */ 166 async initialPermissions() { 167 if (this.bundleName && !this.applicationInfo.groupId.length) { 168 await this.initApplicationInfo(this.applicationInfo); 169 } 170 let reqPermissions = this.applicationInfo.permissions; 171 let reqGroupIds = this.applicationInfo.groupId; 172 173 this.allowedListItem = []; 174 this.bannedListItem = []; 175 176 for (let i = 0; i < reqGroupIds.length; i++) { 177 let id = reqGroupIds[i]; 178 let groupName = groups[id].groupName; 179 let group = groups[id].name; 180 let groupReqPermissions: Permissions[] = []; 181 for (let j = 0; j < reqPermissions.length; j++) { 182 let permission = reqPermissions[j]; 183 if (groups[id].permissions.indexOf(permission) != -1) { 184 groupReqPermissions.push(permission); 185 } 186 } 187 this.isGranted = group === 'LOCATION' ? Constants.PERMISSION_BAN : Constants.PERMISSION_ALLOW; 188 this.folderStatus = [false, false, false]; 189 await this.getStatus(groupReqPermissions, group); 190 191 if ( 192 this.isGranted === Constants.PERMISSION_ALLOW || this.isGranted === Constants.PERMISSION_ALLOWED_ONLY_DURING_USE 193 ) { 194 this.allowedListItem.push(new PermissionObj(groupName, groupReqPermissions, group)); 195 } else { 196 if (group === 'FOLDER' && this.folderStatus.includes(true)) { 197 this.allowedListItem.push(new PermissionObj(groupName, groupReqPermissions, group)); 198 } else { 199 this.bannedListItem.push(new PermissionObj(groupName, groupReqPermissions, group)); 200 } 201 } 202 203 GlobalContext.store('folderStatus', this.folderStatus); 204 } 205 } 206 207 async getStatus(groupReqPermissions: Permissions[], group: string) { 208 if (group === 'LOCATION') { 209 try { 210 let acManager = abilityAccessCtrl.createAtManager(); 211 let fuzzyState = acManager.verifyAccessTokenSync( 212 this.applicationInfo.tokenId, Permission.APPROXIMATELY_LOCATION 213 ); 214 fuzzyState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ? 215 this.isGranted = Constants.PERMISSION_ALLOWED_ONLY_DURING_USE : null; 216 let backgroundState = acManager.verifyAccessTokenSync( 217 this.applicationInfo.tokenId, Permission.LOCATION_IN_BACKGROUND 218 ); 219 backgroundState === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ? 220 this.isGranted = Constants.PERMISSION_ALLOW : null; 221 await acManager.getPermissionFlags(this.applicationInfo.tokenId, Permission.APPROXIMATELY_LOCATION ) 222 .then(flag => { 223 flag === Constants.PERMISSION_ALLOW_THIS_TIME ? this.isGranted = Constants.PERMISSION_ONLY_THIS_TIME : null; 224 }) 225 } catch (err) { 226 Log.error('change location status error: ' + JSON.stringify(err)); 227 } 228 GlobalContext.store('locationStatus', this.isGranted); 229 return true; 230 } 231 for (let i = 0; i < groupReqPermissions.length; i++) { 232 let permission = groupReqPermissions[i]; 233 let res = await verifyAccessToken(this.applicationInfo.tokenId, permission); 234 if (res != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { 235 this.isGranted = Constants.PERMISSION_BAN; 236 } 237 if (group === 'FOLDER' && res === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { 238 switch (permission) { 239 case Permission.READ_WRITE_DOWNLOAD_DIRECTORY: 240 this.folderStatus[0] = true; 241 break; 242 case Permission.READ_WRITE_DESKTOP_DIRECTORY: 243 this.folderStatus[1] = true; 244 break; 245 case Permission.READ_WRITE_DOCUMENTS_DIRECTORY: 246 this.folderStatus[2] = true; 247 break; 248 } 249 } 250 } 251 return true; 252 } 253 254 /** 255 * Lifecycle function, triggered once when this page is displayed 256 */ 257 onPageShow() { 258 this.initialPermissions(); 259 bundleManager.getApplicationInfo( 260 this.applicationInfo.bundleName, bundleManager.ApplicationFlag.GET_APPLICATION_INFO_DEFAULT 261 ).then(appInfo => { 262 let bundleContext = this.context.createBundleContext(this.applicationInfo.bundleName) 263 bundleContext.resourceManager.getStringValue(appInfo.labelId, (error, value) => { 264 if (value) { 265 this.applicationInfo.label = value; 266 GlobalContext.store('applicationInfo', this.applicationInfo); 267 this.label = value 268 } 269 }) 270 }).catch((error: BusinessError) => { 271 Log.error('getApplicationInfo error: ' + JSON.stringify(error)); 272 }) 273 } 274 275 build() { 276 Column() { 277 GridRow({ gutter: Constants.GUTTER, columns: { 278 xs: Constants.XS_COLUMNS, sm: Constants.SM_COLUMNS, md: Constants.MD_COLUMNS, lg: Constants.LG_COLUMNS } }) { 279 GridCol({ 280 span: { xs: Constants.XS_SPAN, sm: Constants.SM_SPAN, md: Constants.MD_SPAN, lg: Constants.LG_SPAN }, 281 offset: { xs: Constants.XS_OFFSET, sm: Constants.SM_OFFSET, md: Constants.MD_OFFSET, lg: Constants.LG_OFFSET } 282 }) { 283 Row() { 284 Column() { 285 Row() { 286 backBar({ title: JSON.stringify(this.label || this.applicationInfo.label), recordable: false }) 287 } 288 Row() { 289 Column() { 290 if (!this.allowedListItem.length && !this.bannedListItem.length) { 291 Row() { 292 List() { 293 ListItem() { 294 Row() { 295 Column() { 296 Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 297 Row() { 298 Column() { 299 Row() { 300 Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 301 Text($r('app.string.no_permission')) 302 .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE) 303 .fontColor($r('sys.color.font_primary')) 304 }.margin({ top: Constants.FLEX_MARGIN_TOP, bottom: Constants.FLEX_MARGIN_BOTTOM }) 305 }.height(Constants.FULL_HEIGHT) 306 }.flexGrow(Constants.FLEX_GROW) 307 .constraintSize({minHeight: Constants.CONSTRAINTSIZE_MINHEIGHT }) 308 } 309 .width(Constants.FULL_WIDTH) 310 .height(Constants.LISTITEM_ROW_HEIGHT) 311 } 312 } 313 } 314 }.padding({ left: Constants.LISTITEM_PADDING_LEFT, right: Constants.LISTITEM_PADDING_RIGHT }) 315 } 316 .backgroundColor($r('sys.color.comp_background_list_card')) 317 .borderRadius($r('sys.float.ohos_id_corner_radius_card')) 318 .padding({ top: Constants.LIST_PADDING_TOP, bottom: Constants.LIST_PADDING_BOTTOM }) 319 }.margin({ top: Constants.ROW_MARGIN_TOP }) 320 .padding({ 321 left: Constants.SECONDARY_LIST_PADDING_LEFT, 322 right: Constants.SECONDARY_LIST_PADDING_RIGHT 323 }) 324 } else { 325 Scroll() { 326 List() { 327 if (this.allowedListItem.length) { 328 ListItem() { 329 Row() { 330 Text($r('app.string.allowed')) 331 .fontSize(Constants.TEXT_SMALL_FONT_SIZE) 332 .fontColor($r('sys.color.font_secondary')) 333 .fontWeight(FontWeight.Medium) 334 .lineHeight(Constants.SUBTITLE_LINE_HEIGHT) 335 }.constraintSize({ minHeight: Constants.SUBTITLE_MIN_HEIGHT }) 336 .width(Constants.FULL_WIDTH) 337 .padding({ top: Constants.SUBTITLE_PADDING_TOP, bottom: Constants.SUBTITLE_PADDING_BOTTOM, 338 left: Constants.SECONDARY_TEXT_MARGIN_LEFT}) 339 } 340 341 ListItem() { 342 Row() { 343 List() { 344 ForEach(this.allowedListItem, (item: PermissionObj) => { 345 this.ListItemLayout(item, Constants.PERMISSION_ALLOW) 346 }, (item: PermissionObj) => JSON.stringify(item)) 347 } 348 .backgroundColor($r('sys.color.comp_background_list_card')) 349 .borderRadius($r('sys.float.ohos_id_corner_radius_card')) 350 .padding(Constants.LIST_PADDING_TOP) 351 .divider({ 352 strokeWidth: Constants.DIVIDER, 353 color: $r('sys.color.comp_divider'), 354 startMargin: Constants.DEFAULT_MARGIN_START, 355 endMargin: Constants.DEFAULT_MARGIN_END 356 }) 357 }.margin({ top: Constants.ROW_MARGIN_TOP }) 358 .padding({ 359 left: Constants.SECONDARY_LIST_PADDING_LEFT, 360 right: Constants.SECONDARY_LIST_PADDING_RIGHT 361 }) 362 } 363 } 364 if (this.bannedListItem.length) { 365 ListItem() { 366 Row() { 367 Text($r('app.string.banned')) 368 .fontSize(Constants.TEXT_SMALL_FONT_SIZE) 369 .fontColor($r('sys.color.font_secondary')) 370 .fontWeight(FontWeight.Medium) 371 .lineHeight(Constants.SUBTITLE_LINE_HEIGHT) 372 }.constraintSize({ minHeight: Constants.SUBTITLE_MIN_HEIGHT }) 373 .width(Constants.FULL_WIDTH) 374 .padding({ top: Constants.SUBTITLE_PADDING_TOP, bottom: Constants.SUBTITLE_PADDING_BOTTOM, 375 left: Constants.SECONDARY_TEXT_MARGIN_LEFT}) 376 } 377 378 ListItem() { 379 Row() { 380 List() { 381 ForEach(this.bannedListItem, (item: PermissionObj) => { 382 this.ListItemLayout(item, Constants.PERMISSION_BAN) 383 }, (item: PermissionObj) => JSON.stringify(item)) 384 } 385 .backgroundColor($r('sys.color.comp_background_list_card')) 386 .borderRadius($r('sys.float.ohos_id_corner_radius_card')) 387 .padding(Constants.LIST_PADDING_TOP) 388 .divider({ 389 strokeWidth: Constants.DIVIDER, 390 color: $r('sys.color.comp_divider'), 391 startMargin: Constants.DEFAULT_MARGIN_START, 392 endMargin: Constants.DEFAULT_MARGIN_END 393 }) 394 }.margin({ top: Constants.ROW_MARGIN_TOP }) 395 .padding({ 396 left: Constants.SECONDARY_LIST_PADDING_LEFT, 397 right: Constants.SECONDARY_LIST_PADDING_RIGHT 398 }) 399 } 400 } 401 } 402 }.scrollBar(BarState.Off) 403 } 404 } 405 .width(Constants.FULL_WIDTH) 406 .height(Constants.FULL_HEIGHT) 407 } 408 .layoutWeight(Constants.LAYOUT_WEIGHT) 409 } 410 } 411 .height(Constants.FULL_HEIGHT) 412 .width(Constants.FULL_WIDTH) 413 .backgroundColor($r('sys.color.background_secondary')) 414 } 415 }.backgroundColor($r('sys.color.background_secondary')) 416 } 417 } 418} 419