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