/*
* Copyright (c) Huawei Device Co., Ltd. 2024-2025. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import sim from '@ohos.telephony.sim';
import ArrayList from '@ohos.util.ArrayList';
import { LogDomain, LogHelper } from '@ohos/basicutils';
import { AbstractInitialAble } from '../base/AbstractInitialAble';
import { SimCardStateManager } from '../manager/SimCardStateManager';
import { SimCardUtils, SimResult } from '../utils/SimCardUtils';
const TAG = 'SimCardVerifyService';
const log: LogHelper = LogHelper.getLogHelper(LogDomain.KG, TAG);
const PUK_WARNING_THRESHOLD: number = 3;
export interface SimCardVerifyCallback {
onPinVerifyCallback: (state: PinVerifyState) => void;
onPukVerifyCallback: (state: PukVerifyState, psd?: string) => void;
}
export enum PinVerifyState {
PIN_CODE_INVALID = 0,
PIN_VERIFY_START,
PIN_VERIFY_SUCCESS,
PIN_VERIFY_FAIL,
PIN_VERIFY_RESULT
}
export enum PukVerifyState {
PUK_CODE_INVALID = 0,
PIN_CODE_INVALID,
PIN_CODE_NO_MATCH,
PUK_VERIFY_START,
PUK_VERIFY_SUCCESS,
PUK_VERIFY_FAIL,
PUK_VERIFY_SHOW_FAIL,
PUK_VERIFY_CONTINUE,
PUK_VERIFY_RESULT,
}
/**
* Sim卡验证服务
*/
export class SimCardVerifyService extends AbstractInitialAble {
private static sInstance: SimCardVerifyService;
private simCardStateManager: SimCardStateManager = SimCardStateManager.getInstance();
public static getInstance(): SimCardVerifyService {
if (SimCardVerifyService.sInstance == null) {
SimCardVerifyService.sInstance = new SimCardVerifyService();
}
return SimCardVerifyService.sInstance;
}
private constructor() {
super();
}
public unlockSimCard(isRememberPin: boolean, password?: string, callBack?: SimCardVerifyCallback,
pukArr?: ArrayList<string>): void {
if (this.simCardStateManager.isPinLocked()) {
this.verifyPin(isRememberPin, (this.simCardStateManager?.getLockQueue().getFirst() ?? 0) as number, password,
callBack);
} else if (this.simCardStateManager.isPukLocked()) {
this.verifyPuk(isRememberPin, (this.simCardStateManager?.getLockQueue().getFirst() ?? 0) as number, password,
callBack, pukArr);
}
}
protected isSupport(): boolean {
return SimCardUtils.isSimCardSupport();
}
protected doInit(): void {
log.showInfo('doInit');
// SIM卡数据初始化
this.simCardStateManager.init();
}
protected doRelease(): void {
log.showInfo('doRelease');
// SIM卡数据释放
this.simCardStateManager.release();
}
private verifyPin(isRememberPin: boolean, slotId: number, password?: string, callBack?: SimCardVerifyCallback): void {
log.showInfo('unlock pin start');
if (!SimCardUtils.isValidPin(password)) {
log.showError('invalid pin format');
callBack?.onPinVerifyCallback(PinVerifyState.PIN_CODE_INVALID);// state1
return;
}
callBack?.onPinVerifyCallback(PinVerifyState.PIN_VERIFY_START);
const result: SimResult = SimCardUtils.unlockPin(slotId, password, async () => {
SimCardUtils.getSimState(slotId).then(async (state: sim.SimState) => {
let unlockPinSuccess: boolean = result.retCode === 0 || state !== sim.SimState.SIM_STATE_LOCKED;
if (unlockPinSuccess && isRememberPin) {
SimCardUtils.setPinSavingFlag(slotId, isRememberPin, password);
}
if (unlockPinSuccess) {
log.showInfo('unlock pin success');
this.simCardStateManager.getLockQueue().remove(slotId);
callBack?.onPinVerifyCallback(PinVerifyState.PIN_VERIFY_RESULT);
}
await this.simCardStateManager.updateCardState(slotId, state);
if (result.retCode !== 0) {
callBack?.onPinVerifyCallback(PinVerifyState.PIN_VERIFY_FAIL);
} else {
callBack?.onPinVerifyCallback(PinVerifyState.PIN_VERIFY_SUCCESS);
}
})
.catch((err: Error) => {
log.showError(`getSimState error. errCode ${err?.message}`);
})
});
}
/**
* Puk码校验输入pukArr包含8位puk码和新设置的pin码,pin码需要输入两次
*/
private verifyPuk(isRememberPin: boolean, slotId: number, password?: string, callBack?: SimCardVerifyCallback,
pukArr?: ArrayList<string>): void {
if (!pukArr) {
log.showError('verifyPuk error, pukArr is undefined');
return;
}
if (pukArr.length === 0 && !SimCardUtils.isValidPukCode(password)) {
log.showError('invalid puk format');
callBack?.onPukVerifyCallback(PukVerifyState.PUK_CODE_INVALID);
return;
}
if (pukArr.length === 1 && !SimCardUtils.isValidPin(password)) {
log.showError('invalid new pin format');
callBack?.onPukVerifyCallback(PukVerifyState.PIN_CODE_INVALID);
return;
}
if (pukArr.length === 2 && !SimCardUtils.isMatchedPin(pukArr.convertToArray(), password)) {
log.showError('confirm pin not matched');
callBack?.onPukVerifyCallback(PukVerifyState.PIN_CODE_NO_MATCH);
return;
}
if (pukArr.length !== 2) {
callBack?.onPukVerifyCallback(PukVerifyState.PUK_VERIFY_CONTINUE, password);
return;
}
this.unlockPukInner(isRememberPin, slotId, password, callBack, pukArr);
}
private unlockPukInner(isRememberPin: boolean, slotId: number, password?: string, callBack?: SimCardVerifyCallback,
pukArr?: ArrayList<string>): void {
log.showInfo('unlock puk start');
callBack?.onPukVerifyCallback(PukVerifyState.PUK_VERIFY_START);
const result: SimResult = SimCardUtils.unlockPuk(slotId, pukArr, async () => {
SimCardUtils.getSimState(slotId).then(async (state: sim.SimState) => {
if (isRememberPin) {
SimCardUtils.setPinSavingFlag(slotId, isRememberPin, password);
}
if (result.retCode === 0 || state !== sim.SimState.SIM_STATE_LOCKED) {
log.showInfo('unlock puk success');
SimCardUtils.updatePinSaving(slotId, password);
this.simCardStateManager.getLockQueue().remove(slotId);
callBack?.onPukVerifyCallback(PukVerifyState.PUK_VERIFY_RESULT);
}
await this.simCardStateManager.updateCardState(slotId, state);
if (result.retCode !== 0) {
let isPukRemainWarning: boolean = ((result.remain ?? 0) as number) <= PUK_WARNING_THRESHOLD;
callBack?.onPukVerifyCallback(isPukRemainWarning ? PukVerifyState.PUK_VERIFY_SHOW_FAIL :
PukVerifyState.PUK_VERIFY_FAIL);
} else {
callBack?.onPukVerifyCallback(PukVerifyState.PUK_VERIFY_SUCCESS);
}
})
.catch((err: Error) => {
log.showError(`getSimState error. errCode ${err?.message}`);
})
});
}
}