1/** 2 * Copyright (c) 2024 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 hiLog from '@ohos.hilog'; 17import userAuth from '@ohos.userIAM.userAuth'; 18 19const DOMAIN: number = 0x0007; 20const TAG: string = 'useriam_auth_icon'; 21const ICON_UNAVAILABLE: number = 0; 22const ICON_AVAILABLE: number = 1; 23const TIMEOUT_MILLISECONDS: number = 5000; 24const INVALID_PARAMETERS: number = 401; 25const FACE_ICON_RESOURCE: string = 'sys.symbol.face'; 26const FINGERPRINT_ICON_RESOURCE: string = 'sys.symbol.touchid'; 27 28/** 29 * Declare UserAuthIcon, use for user authentication. 30 * 31 * @syscap SystemCapability.UserIAM.UserAuth.Core 32 * @since 12 33 */ 34@Component 35export struct UserAuthIcon { 36 /** 37 * Set user auth parameter. 38 * 39 * @type { userAuth.AuthParam } 40 * @syscap SystemCapability.UserIAM.UserAuth.Core 41 * @since 12 42 */ 43 authParam: userAuth.AuthParam = { 44 challenge: new Uint8Array(), 45 authType: [], 46 authTrustLevel: userAuth.AuthTrustLevel.ATL1 47 }; 48 /** 49 * Set auth widget parameter. 50 * 51 * @type { userAuth.WidgetParam } 52 * @syscap SystemCapability.UserIAM.UserAuth.Core 53 * @since 12 54 */ 55 widgetParam: userAuth.WidgetParam = { 56 title: '' 57 }; 58 /** 59 * Set the height of the icon, width and height ratio 1:1. 60 * 61 * @type { ?Dimension } 62 * @default 64 63 * @syscap SystemCapability.UserIAM.UserAuth.Core 64 * @since 12 65 */ 66 iconHeight?: Dimension = 64; 67 /** 68 * Set the color of the icon. 69 * 70 * @type { ?ResourceColor } 71 * @default $r('sys.color.ohos_id_color_activated') 72 * @syscap SystemCapability.UserIAM.UserAuth.Core 73 * @since 12 74 */ 75 iconColor?: ResourceColor = $r('sys.color.ohos_id_color_activated'); 76 authFlag: number = ICON_UNAVAILABLE; 77 @State imageSource: string = ''; 78 /** 79 * The authentication result code is returned through the callback. 80 * If the authentication is passed, the authentication token and auth type will be returned. 81 * You need to apply for permission:ohos.permission.ACCESS_BIOMETRIC to use user authentication ability. 82 * 83 * @param { userAuth.UserAuthResult } result - Authentication result information. 84 * @syscap SystemCapability.UserIAM.UserAuth.Core 85 * @since 12 86 */ 87 onAuthResult: (result: userAuth.UserAuthResult) => void = (result: userAuth.UserAuthResult) => { 88 }; 89 /** 90 * When user click the icon, it will be returned through this callback. 91 * 92 * @syscap SystemCapability.UserIAM.UserAuth.Core 93 * @since 12 94 */ 95 onIconClick: () => void = () => { 96 }; 97 98 private initImageSource(authTypes: userAuth.UserAuthType[], authTrustLevel: userAuth.AuthTrustLevel): void { 99 if (authTypes.includes(userAuth.UserAuthType.FACE) && (!authTypes.includes(userAuth.UserAuthType.FINGERPRINT))) { 100 // Handle the situation where the authTypes parameter contains face type but not contains fingerprint type. 101 this.authFlag = ICON_AVAILABLE; 102 this.imageSource = FACE_ICON_RESOURCE; 103 return; 104 } 105 if ((!authTypes.includes(userAuth.UserAuthType.FACE)) && authTypes.includes(userAuth.UserAuthType.FINGERPRINT)) { 106 // Handle the situation where the authTypes parameter contains fingerprint type but not contains face type. 107 this.authFlag = ICON_AVAILABLE; 108 this.imageSource = FINGERPRINT_ICON_RESOURCE; 109 return; 110 } 111 if (authTypes.includes(userAuth.UserAuthType.FACE) && authTypes.includes(userAuth.UserAuthType.FINGERPRINT) && 112 authTypes.includes(userAuth.UserAuthType.PIN)) { 113 // Handle the situation where the authTypes parameter contains face, fingerprint, and PIN types at the same time. 114 this.handleAllAuthTypeCase(authTrustLevel); 115 return; 116 } 117 if (authTypes.includes(userAuth.UserAuthType.FACE) && authTypes.includes(userAuth.UserAuthType.FINGERPRINT) && 118 !authTypes.includes(userAuth.UserAuthType.PIN)) { 119 // Handle the situation where the authTypes parameter contains face, fingerprint, but not contains PIN types at 120 // the same time. 121 this.authFlag = ICON_UNAVAILABLE; 122 this.info('incorrect parameters.'); 123 this.onAuthResult({ result: INVALID_PARAMETERS }); 124 this.imageSource = ''; 125 return; 126 } 127 // Default processing, includes the situation where the authTypes parameter only contains face and fingerprint 128 // types or the situation where the authTypes parameter only contains PIN type. 129 this.authFlag = ICON_UNAVAILABLE; 130 this.info('incorrect parameters.'); 131 this.onAuthResult({ result: userAuth.UserAuthResultCode.TYPE_NOT_SUPPORT }); 132 this.imageSource = ''; 133 return; 134 } 135 136 private handleAllAuthTypeCase(authTrustLevel: userAuth.AuthTrustLevel): void { 137 if (this.checkAuthTypeSupported(userAuth.UserAuthType.FACE, authTrustLevel)) { 138 this.info('face auth available.'); 139 this.authFlag = ICON_AVAILABLE; 140 this.imageSource = FACE_ICON_RESOURCE; 141 return; 142 } 143 if (this.checkAuthTypeSupported(userAuth.UserAuthType.FINGERPRINT, authTrustLevel)) { 144 this.info('finger auth available.'); 145 this.authFlag = ICON_AVAILABLE; 146 this.imageSource = FINGERPRINT_ICON_RESOURCE; 147 return; 148 } 149 this.authFlag = ICON_AVAILABLE; 150 this.imageSource = FACE_ICON_RESOURCE; 151 return; 152 } 153 154 private checkAuthTypeSupported(authType: userAuth.UserAuthType, authTrustLevel: userAuth.AuthTrustLevel): boolean { 155 this.info(`check if it is supported, authType: ${authType} authTrustLevel: ${authTrustLevel}.`); 156 try { 157 userAuth.getAvailableStatus(authType, authTrustLevel); 158 this.info('current auth trust level is supported.'); 159 return true; 160 } catch (error) { 161 this.error(`current auth trust level is not supported, error = ${error}.`); 162 return false; 163 } 164 } 165 166 private info(format: string): void { 167 if (hiLog.isLoggable(DOMAIN, TAG, hiLog.LogLevel.INFO)) { 168 hiLog.info(DOMAIN, TAG, format); 169 } 170 } 171 172 private error(format: string): void { 173 if (hiLog.isLoggable(DOMAIN, TAG, hiLog.LogLevel.ERROR)) { 174 hiLog.error(DOMAIN, TAG, format); 175 } 176 } 177 178 aboutToAppear(): void { 179 this.info('before init image source.'); 180 if (this.authParam.authType === undefined || this.authParam.authTrustLevel === undefined) { 181 this.authFlag = ICON_UNAVAILABLE; 182 this.info('incorrect parameters.'); 183 this.onAuthResult({ result: INVALID_PARAMETERS }); 184 this.imageSource = ''; 185 return; 186 } 187 this.initImageSource(this.authParam.authType, this.authParam.authTrustLevel); 188 this.info(`after init image source, imageSource = ${this.imageSource}.`); 189 } 190 191 build() { 192 Row() { 193 Column() { 194 SymbolGlyph($r(this.imageSource)) 195 .fontSize(this.iconHeight) 196 .fontColor([this.iconColor]) 197 .onClick(() => { 198 this.info('start handle click event.'); 199 if (this.onIconClick !== undefined) { 200 this.info('click event has response.'); 201 this.onIconClick(); 202 } 203 if (this.authFlag === ICON_AVAILABLE) { 204 try { 205 let userAuthInstance: userAuth.UserAuthInstance = 206 userAuth.getUserAuthInstance(this.authParam, this.widgetParam); 207 let timer: number = setTimeout(() => { 208 this.error('auth timeout.'); 209 userAuthInstance.cancel(); 210 this.onAuthResult({ result: userAuth.UserAuthResultCode.GENERAL_ERROR }); 211 }, TIMEOUT_MILLISECONDS) 212 this.info('get userAuth instance success.'); 213 userAuthInstance.on('result', { 214 onResult: (result) => { 215 this.info(`userAuthInstance callback result = ${JSON.stringify(result)}.`); 216 this.onAuthResult(result); 217 userAuthInstance.off('result'); 218 } 219 }); 220 this.info('auth before start.'); 221 userAuthInstance.start(); 222 this.info('auth start success.'); 223 clearTimeout(timer); 224 } catch (error) { 225 if (error) { 226 this.error(`auth catch error, code: ${error.code}, message: ${error.message}`); 227 this.onAuthResult({ result: error.code }); 228 return; 229 } 230 this.error('auth error.'); 231 this.onAuthResult({ result: userAuth.UserAuthResultCode.GENERAL_ERROR }); 232 } 233 } 234 this.info('end handle click event.'); 235 }) 236 } 237 } 238 } 239} 240