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