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 { alphabetIndexerComponent } from '../common/components/alphabeticalIndex'; 18import { textInput } from '../common/components/search'; 19import router from '@ohos.router'; 20import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; 21import { BusinessError } from '@ohos.base'; 22import { Log, verifyAccessToken, indexValue, sortByName } from '../common/utils/utils'; 23import { 24 ApplicationObj, 25 PermissionInfo, 26 RouterParams2, 27 PermissionApplications, 28 AppInfo 29} from '../common/model/typedef'; 30import { GlobalContext } from '../common/utils/globalContext'; 31import Constants from '../common/utils/constant'; 32import { permissionInfos } from '../common/model/permissionGroup'; 33import { Permission } from '../common/model/definition'; 34 35@Extend(Image)function customizeImage(width: number, height: number) { 36 .objectFit(ImageFit.Contain) 37 .width(width) 38 .height(height) 39} 40 41@Entry 42@Component 43struct locationInfoPage { 44 private backTitle: ResourceStr = (router.getParams() as RouterParams2).backTitle; 45 46 build() { 47 GridRow({ gutter: Constants.GUTTER, columns: { 48 xs: Constants.XS_COLUMNS, sm: Constants.SM_COLUMNS, md: Constants.MD_COLUMNS, lg: Constants.LG_COLUMNS } }) { 49 GridCol({ 50 span: { xs: Constants.XS_SPAN, sm: Constants.SM_SPAN, md: Constants.MD_SPAN, lg: Constants.LG_SPAN }, 51 offset: { xs: Constants.XS_OFFSET, sm: Constants.SM_OFFSET, md: Constants.MD_OFFSET, lg: Constants.LG_OFFSET } 52 }) { 53 Row() { 54 Column() { 55 Row() { 56 backBar({ title: JSON.stringify(this.backTitle), recordable: false }) 57 } 58 Row() { 59 Column() { 60 applicationItem() 61 62 }.width(Constants.FULL_WIDTH) 63 } 64 .layoutWeight(Constants.LAYOUT_WEIGHT) 65 } 66 } 67 .height(Constants.FULL_HEIGHT) 68 .width(Constants.FULL_WIDTH) 69 .backgroundColor($r('sys.color.background_secondary')) 70 } 71 }.backgroundColor($r('sys.color.background_secondary')) 72 } 73} 74 75@Component 76struct applicationItem { 77 private list: PermissionApplications[] = (router.getParams() as RouterParams2).list; 78 private permissionName: Permission = (router.getParams() as RouterParams2).permissionName; 79 @State permissionNum: number = Constants.PERMISSION_NUM; // permission num 80 @State toggleIsOn: boolean[] = []; // toggle switch state array 81 @State isRisk: boolean[] = []; 82 @State isFirst: boolean[] = []; 83 @State applicationList: ApplicationObj[] = []; // application info array 84 @State searchResult: boolean = true; // search results 85 @State selectedIndex: number = 0; 86 @State permissionInfo: PermissionInfo | undefined = undefined; 87 @State allBundleInfo: AppInfo[] = GlobalContext.load('allBundleInfo'); 88 scroller: Scroller = new Scroller(); 89 90 @Builder ListItemLayout(item: ApplicationObj) { 91 ListItem() { 92 Row() { 93 Column() { 94 Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 95 Row() { 96 Image(item.icon) 97 .customizeImage(Constants.AUTHORITY_IMAGE_WIDTH, Constants.AUTHORITY_IMAGE_HEIGHT) 98 .margin({ right: Constants.AUTHORITY_IMAGE_MARGIN_RIGHT }) 99 Column() { 100 Text(item.label) 101 .width(Constants.MAXIMUM_HEADER_WIDTH) 102 .maxLines(Constants.MAXIMUM_HEADER_LINES) 103 .textOverflow({ overflow: TextOverflow.Ellipsis }) 104 .fontSize(Constants.TEXT_MIDDLE_FONT_SIZE) 105 .fontWeight(FontWeight.Medium) 106 .fontColor($r('sys.color.font_primary')) 107 if (this.isRisk[item.index]) { 108 Text($r('app.string.risk_warning')) 109 .fontSize(Constants.TEXT_SMALL_FONT_SIZE) 110 .fontColor($r('sys.color.font_secondary')) 111 } 112 }.flexGrow(Constants.FLEX_GROW) 113 .alignItems(HorizontalAlign.Start) 114 Toggle({ type: ToggleType.Switch, isOn: this.toggleIsOn[item.index] }) 115 .selectedColor($r('sys.color.icon_emphasize')) 116 .switchPointColor($r('sys.color.comp_background_primary_contrary')) 117 .padding({ right: 0 }) 118 .width(Constants.AUTHORITY_TOGGLE_WIDTH) 119 .height(Constants.AUTHORITY_TOGGLE_HEIGHT) 120 .onChange((isOn: boolean) => { 121 if (item.permission === undefined) { 122 return; 123 } 124 if (this.isFirst[item.index] && isOn) { 125 this.isFirst[item.index] = false; 126 return; 127 } 128 this.isFirst[item.index] = false; 129 if (isOn) { 130 this.grantUserGrantedPermission(item.accessTokenId, item.permission, item.index); 131 } else { 132 this.revokeUserGrantedPermission(item.accessTokenId, item.permission, item.index); 133 } 134 }) 135 } 136 .width(Constants.FULL_WIDTH) 137 .height(Constants.AUTHORITY_ROW_HEIGHT) 138 .constraintSize({ minHeight: Constants.AUTHORITY_CONSTRAINTSIZE_MINHEIGHT }) 139 } 140 }.onClick(() => { 141 }) 142 } 143 }.padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END }) 144 .enabled(!this.isRisk[item.index]) 145 .opacity(this.isRisk[item.index] ? $r('sys.float.ohos_id_alpha_disabled') : 1) 146 } 147 148 /** 149 * Grant permissions to the app 150 * @param {Number} accessTokenId 151 * @param {String} permission permission name 152 * @param {Number} index Array index to modify permission status 153 */ 154 grantUserGrantedPermission(accessTokenId: number, permission: Permissions, index: number) { 155 abilityAccessCtrl.createAtManager().grantUserGrantedPermission( 156 accessTokenId, permission, Constants.PERMISSION_FLAG).then(() => { 157 // result: 0 Authorization succeeded; result: -1 Authorization failed 158 this.toggleIsOn[index] = true; 159 let num = this.toggleIsOn.filter(item => item === true).length; 160 this.permissionNum = num; 161 }).catch((error: BusinessError) => { 162 this.toggleIsOn[index] = false; 163 Log.error('grantUserGrantedPermission failed. Cause: ' + JSON.stringify(error)); 164 }) 165 } 166 167 /** 168 * Deauthorize the app 169 * @param {Number} accessTokenId 170 * @param {String} permission permission name 171 * @param {Number} index Array index to modify permission status 172 */ 173 revokeUserGrantedPermission(accessTokenId: number, permission: Permissions, index: number) { 174 abilityAccessCtrl.createAtManager().revokeUserGrantedPermission( 175 accessTokenId, permission, Constants.PERMISSION_FLAG).then(() => { 176 // result: 0 successfully cancel the authorization; result: -1 cancel the authorization failed 177 this.toggleIsOn[index] = false; 178 let num = this.toggleIsOn.filter(item => item === true).length; 179 this.permissionNum = num; 180 }).catch(() => { 181 this.toggleIsOn[index] = true; 182 }) 183 } 184 185 /** 186 * Lifecycle function, executed when the page is initialized 187 */ 188 aboutToAppear() { 189 let bundleNames = this.list.length > 0 ? this.list[0].bundleNames : this.list; 190 this.permissionInfo = permissionInfos.get(this.permissionName); 191 192 let atManager = abilityAccessCtrl.createAtManager(); 193 for (let i = 0; i < bundleNames.length; i++) { 194 // Get BundleInfo based on bundle name 195 this.allBundleInfo.forEach(bundleInfo => { 196 if (bundleInfo.bundleName === bundleNames[i]) { 197 this.applicationList.push( 198 new ApplicationObj( 199 bundleInfo.label, 200 bundleInfo.icon, 201 i, 202 bundleInfo.tokenId, 203 this.list[0].permission, 204 bundleInfo.zhTag, 205 bundleInfo.indexTag, 206 bundleInfo.language) // Get the first letter in the returned initials array 207 ); 208 verifyAccessToken(bundleInfo.tokenId, this.list[0].permission).then(data => { 209 // 0: have permission; -1: no permission 210 if (data === Constants.PERMISSION_INDEX) { 211 this.toggleIsOn[i] = true; 212 this.isFirst[i] = true; 213 this.permissionNum++; 214 } else { 215 this.toggleIsOn[i] = false; 216 this.isFirst[i] = false; 217 } 218 }) 219 this.isRisk[i] = false; 220 try { 221 atManager.getPermissionFlags(bundleInfo.tokenId, this.list[0].permission).then(data => { 222 if (data == Constants.PERMISSION_POLICY_FIXED) { 223 this.isRisk[i] = true; 224 } 225 }) 226 } catch (err) { 227 Log.error('getPermissionFlags error: ' + JSON.stringify(err)); 228 } 229 } 230 }) 231 } 232 } 233 234 build() { 235 Column() { 236 Row() { 237 textInput({ 238 applicationItem: $applicationList, 239 searchResult: $searchResult 240 }) 241 }.padding({ 242 left: Constants.AUTHORITY_TEXTINPUT_PADDING_LEFT, 243 right: Constants.AUTHORITY_TEXTINPUT_PADDING_RIGHT 244 }) 245 Flex({ alignItems:ItemAlign.Start, justifyContent: FlexAlign.Start }) { 246 Column() { 247 Flex({ justifyContent: FlexAlign.Start }) { 248 if (this.permissionNum > 0) { 249 Text( 250 this.permissionInfo?.enableDescription ? 251 $r(this.permissionInfo.enableDescription, String(this.permissionNum)) : 252 '' 253 ) 254 .fontSize(Constants.TEXT_SMALL_FONT_SIZE) 255 .fontColor($r('sys.color.font_secondary')) 256 .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP }) 257 } else { 258 Text(this.permissionInfo?.forbiddenDescription) 259 .fontSize(Constants.TEXT_SMALL_FONT_SIZE) 260 .fontColor($r('sys.color.font_secondary')) 261 .margin({ top: Constants.AUTHORITY_TEXT_MARGIN_TOP }) 262 } 263 }.padding({ left: Constants.DEFAULT_PADDING_START, right: Constants.DEFAULT_PADDING_END }) 264 .margin({ bottom: Constants.AUTHORITY_ROW_MARGIN_BOTTOM }) 265 Row() { 266 Column() { 267 if (!this.applicationList.length) { 268 if (this.searchResult) { 269 Row() {} 270 } else { 271 Row() { 272 Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 273 Image($r('app.media.searchnoresult')) 274 .customizeImage(Constants.SEARCHNORESULT_IMAGE_WIDTH, Constants.SEARCHNORESULT_IMAGE_HEIGHT) 275 } 276 } 277 } 278 } else { 279 Row() { 280 List({ scroller: this.scroller }) { 281 ForEach(sortByName(this.applicationList), (item: ApplicationObj) => { 282 this.ListItemLayout(item) 283 }, (item: ApplicationObj) => JSON.stringify(item)) 284 } 285 .backgroundColor($r('sys.color.comp_background_list_card')) 286 .borderRadius($r('sys.float.ohos_id_corner_radius_card')) 287 .padding({ top: Constants.LIST_PADDING_TOP, bottom: Constants.LIST_PADDING_BOTTOM }) 288 .divider({ 289 strokeWidth: Constants.DIVIDER, 290 color: $r('sys.color.comp_divider'), 291 startMargin: Constants.DIVIDER_MARGIN_RIGHT_APPLICATION, 292 endMargin: Constants.DEFAULT_MARGIN_END 293 }) 294 .onScrollIndex((start, end) => { 295 GlobalContext.getContext().set('scroller', this.scroller); 296 if (this.applicationList.length > 0) { 297 let alphabeticalIndex = sortByName(this.applicationList)[start].indexTag; 298 let index = indexValue.indexOf(alphabeticalIndex); 299 this.selectedIndex = index >= 0 ? index : 0; 300 } 301 }) 302 } 303 } 304 }.width(Constants.FULL_WIDTH) 305 .margin({ bottom: Constants.AUTHORITY_LIST_MARGIN_BOTTOM }) 306 } 307 }.padding({ left: Constants.AUTHORITY_LISTITEM_PADDING_LEFT }) 308 Column() { 309 alphabetIndexerComponent({ applicationItem: $applicationList, index: $selectedIndex }) 310 }.width(Constants.AUTHORITY_ALPHABETINDEX_WIDTH) 311 .padding({ top: Constants.AUTHORITY_ALPHABETINDEX_PADDING_TOP }) 312 .margin({ bottom: Constants.APPLICATION_LIST_MARGIN_BOTTOM }) 313 }.flexGrow(Constants.FLEX_GROW) 314 }.height(Constants.FULL_HEIGHT) 315 } 316} 317