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