• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2022 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 */
15import {Log, Trace, WriteFaultLog, FaultID, createOrGet, ScreenLockStatus} from '@ohos/common'
16import ScreenLockModel from './screenLockModel';
17import AccountModel, {AuthType, AuthSubType, AuthTurstLevel} from './accountsModel'
18import Router from '@system.router';
19import commonEvent from '@ohos.commonEvent';
20import hiDebug from '@ohos.hidebug';
21import systemParameter from '@ohos.systemparameter';
22import {CommonEventPublishData} from 'commonEvent/commonEventPublishData';
23import {Callback} from '@ohos.base';
24import {UIContext} from '@ohos.arkui.UIContext';
25
26const TAG = 'ScreenLock-ScreenLockService';
27const URI_DIGITALPASSWORD = 'pages/digitalPassword'
28const URI_MIXEDPASSWORD = 'pages/mixedPassword'
29const URI_CUSTOMPASSWORD = 'pages/customPassword'
30
31//Event type name
32const EVENT_BEGIN_WAKEUP: string = 'beginWakeUp'
33const EVENT_END_WAKEUP: string = 'endWakeUp'
34const EVENT_BEGIN_SCREENON: string = 'beginScreenOn'
35const EVENT_END_SCREEN_ON: string = 'endScreenOn'
36const EVENT_BEGIN_SCREENOFF: string = 'beginScreenOff'
37const EVENT_END_SCREENOFF: string = 'endScreenOff'
38const EVENT_UNLOCK_SCREEN: string = 'unlockScreen'
39const EVENT_LOCK_SCREEN: string = 'lockScreen'
40const EVENT_BEGIN_EXITANIMATION: string = 'beginExitAnimation'
41const EVENT_BEGIN_SLEEP: string = 'beginSleep'
42const EVENT_END_SLEEP: string = 'endSleep'
43const EVENT_CHANGE_USER: string = 'changeUser'
44const EVENT_SCREENLOCK_ENABLE: string = 'screenlockEnabled'
45const EVENT_SYSTEM_READY: string = 'systemReady'
46
47const SERVICE_RESTART: string = 'serviceRestart'
48
49const LOCK_SCREEN_RESULT: string = 'lockScreenResult'
50const UNLOCK_SCREEN_RESULT: string = 'unlockScreenResult'
51const SCREENLOCK_DRAW_DONE: string = 'screenDrawDone'
52
53const ACTIVATING_TYPE = "activating"
54const ACTIVATE_TYPE = "activate"
55const ACTIVATING_EVENT = "activatingEvent"
56const ACTIVATE_EVENT = "activateEvent"
57
58const CHALLENGE_INT = 0
59
60const MAIN_USER = 100
61
62const MEMORY_MONITOR_PERIOD_MS = 600000
63const MEMORY_MONITOR_LIMIT_KB = 120 * 1024
64
65export {AuthType, AuthSubType};
66
67export enum UnlockResult {
68    Success = 0,
69    Fail = 1,
70    Cancel = 2
71}
72
73export enum LockResult {
74    Success = 0,
75    Fail = 1,
76    Cancel = 2
77}
78
79let mRouterPath: string = ""
80
81let mWillRecognizeFace: boolean = false
82
83let mUnLockBeginAnimation: Callback<Callback<void>> = (callback: Callback<void>) => {
84    callback()
85}
86
87export class ScreenLockService {
88    accountModel: AccountModel = new AccountModel()
89    screenLockModel: ScreenLockModel = new ScreenLockModel()
90    currentLockStatus : ScreenLockStatus;
91    memoryMonitor: number = -1;
92    init() {
93        Log.showDebug(TAG, 'init');
94        this.startMonitorMemory();
95        this.accountModel.modelInit();
96        this.monitorEvents();
97        this.accountModel.updateAllUsers()
98        this.checkPinAuthProperty(() => {
99            Log.showInfo(TAG, `checkPinAuthProperty back`)
100            this.authUserByFace()
101        })
102    }
103
104    monitorEvents() {
105        Log.showDebug(TAG, 'registered events start');
106        this.screenLockModel.eventListener((typeName: String) => {
107            switch (typeName) {
108            // System ready on device boot
109                case EVENT_SYSTEM_READY:
110                    Log.showInfo(TAG, `EVENT_SYSTEM_READY event`);
111                    this.lockScreen();
112                    break;
113            //Bright screen
114                case EVENT_END_SCREEN_ON:
115                    Log.showInfo(TAG, `EVENT_END_SCREEN_ON event`);
116                    this.authUserByFace()
117                    AppStorage.SetOrCreate('deviceStatus', EVENT_END_SCREEN_ON);
118                    break;
119            //The device is going to sleep
120                case EVENT_BEGIN_SLEEP:
121                    Trace.start(Trace.CORE_METHOD_SLEEP_TO_LOCK_SCREEN);
122                    Log.showInfo(TAG, `EVENT_BEGIN_SLEEP event`);
123                    this.backPage();
124                    this.lockScreen();
125                    this.accountModel.updateAllUsers()
126                    AppStorage.SetOrCreate('deviceStatus', EVENT_BEGIN_SLEEP);
127                    break;
128            //unlock request was received
129                case EVENT_UNLOCK_SCREEN:
130                    Log.showInfo(TAG, `EVENT_UNLOCK_SCREEN event`);
131                    this.unlockScreen();
132                    break;
133            //lock request was received
134                case EVENT_LOCK_SCREEN:
135                    Log.showInfo(TAG, `EVENT_LOCK_SCREEN event`);
136                    this.lockScreen();
137                    break;
138                case SERVICE_RESTART:
139                    setTimeout(() => {
140                        this.monitorEvents();
141                        this.lockScreen();
142                    }, 2000);
143                    break;
144                default:
145                    Log.showError(TAG, `eventListener:typeName ${typeName}`)
146            }
147        })
148
149        this.accountModel.eventListener(ACTIVATING_TYPE, ACTIVATING_EVENT, () => {
150            Log.showInfo(TAG, `ACTIVATING_TYPE event`);
151        })
152
153        this.accountModel.eventListener(ACTIVATE_TYPE, ACTIVATE_EVENT, () => {
154            Log.showInfo(TAG, `ACTIVATE_TYPE event`);
155            this.lockScreen();
156            this.accountModel.updateAllUsers()
157            this.checkPinAuthProperty(() => {
158                Log.showInfo(TAG, `checkPinAuthProperty back`)
159                this.authUserByFace()
160            })
161        })
162
163        this.accountModel.commonEventListener(()=>{
164            Log.showInfo(TAG, `commonEventListener event`);
165            this.accountModel.updateAllUsers();
166        })
167
168        Log.showDebug(TAG, 'registered events end');
169    }
170
171    lockScreen() {
172        Trace.start(Trace.CORE_METHOD_SHOW_LOCK_SCREEN);
173        Log.showDebug(TAG, `lockScreen`);
174
175        //lock the screen
176        this.screenLockModel.showScreenLockWindow(() => {
177            Log.showInfo(TAG, `showScreenLockWindow finish`);
178            this.checkPinAuthProperty(() => {
179            });
180            Log.showInfo(TAG, `screenlock status:${this.currentLockStatus}, userId : ${this.accountModel.getCurrentUserId()}`);
181            if (this.currentLockStatus == ScreenLockStatus.Locking) {
182                Log.showInfo(TAG, `had locked, no need to publish lock_screen`);
183            } else {
184                this.notifyLockScreenResult(LockResult.Success)
185                systemParameter.set('bootevent.lockscreen.ready','true')
186                this.currentLockStatus = ScreenLockStatus.Locking;
187            }
188        });
189    }
190
191    private checkPinAuthProperty(callback: Callback<void>) {
192        Log.showDebug(TAG, "checkPinAuthProperty")
193        this.accountModel.getAuthProperty(AuthType.PIN, (properties) => {
194            Log.showInfo(TAG, `checkPinAuthProperty: AUTH_SUB_TYPE:${properties.authSubType}`);
195            switch (properties.authSubType) {
196                case AuthSubType.PIN_SIX:
197                    AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Locking);
198                    mRouterPath = URI_DIGITALPASSWORD;
199                    this.checkFaceAuthProperty(() => {
200                        callback()
201                    })
202                    break;
203                case AuthSubType.PIN_MIXED:
204                    AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Locking);
205                    mRouterPath = URI_MIXEDPASSWORD;
206                    this.checkFaceAuthProperty(() => {
207                        callback()
208                    })
209                    break;
210                case AuthSubType.PIN_NUMBER:
211                    AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Locking);
212                    mRouterPath = URI_CUSTOMPASSWORD;
213                    this.checkFaceAuthProperty(() => {
214                        callback()
215                    })
216                    break;
217                default:
218                    AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Unlock);
219                    mWillRecognizeFace = false
220            }
221        })
222    }
223
224    private checkFaceAuthProperty(callback: Callback<void>) {
225        Log.showDebug(TAG, "checkFaceAuthProperty")
226        this.accountModel.getAuthProperty(AuthType.FACE, (properties) => {
227            Log.showInfo(TAG, `checkFaceAuthProperty:AUTH_SUB_TYPE:${properties.authSubType}`);
228            switch (properties.authSubType) {
229                case AuthSubType.FACE_2D:
230                case AuthSubType.FACE_3D:
231                    mWillRecognizeFace = true
232                    callback()
233                    break;
234                default:
235                    mWillRecognizeFace = false
236            }
237        })
238    }
239
240    unlockScreen() {
241        Log.showInfo(TAG, `unlockScreen`);
242        this.accountModel.isActivateAccount((isActivate: boolean) => {
243            if (!isActivate) {
244                return
245            }
246            mUnLockBeginAnimation(() => {
247                let status = AppStorage.Link('lockStatus')
248                Log.showDebug(TAG, `unlocking lockStatus:${JSON.stringify(status?.get())}`);
249                if (status?.get() == ScreenLockStatus.Unlock) {
250                    Log.showInfo(TAG, `unlock the screen`);
251                    this.unlocking();
252                } else {
253                    let slidestatus = AppStorage.Get('slidestatus')
254                    if(!slidestatus){
255                        AppStorage.SetOrCreate('slidestatus', true);
256                        const UIContext: UIContext = AppStorage.get('UIContext');
257                        Log.showInfo(TAG, `this.UIContext is ${UIContext}`)
258                        Log.showInfo(TAG, `unlockScreen Router.push`);
259                        UIContext.getRouter().pushUrl({ url: mRouterPath })
260                    }
261                }
262            })
263        })
264    }
265
266    unlocking() {
267        Log.showInfo(TAG, `unlocking`);
268        //set the lockStatus to 'Unlock'
269        AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Unlock);
270        this.currentLockStatus = ScreenLockStatus.Unlock;
271        AppStorage.SetOrCreate('slidestatus', false);
272        //unlock the screen
273        this.screenLockModel.hiddenScreenLockWindow(() => {
274            Log.showInfo(TAG, `hiddenScreenLockWindow finish`);
275            //notify the base service that the unlock is completed
276            this.notifyUnlockScreenResult(UnlockResult.Success);
277        });
278    }
279
280    notifyUnlockScreenResult(result: UnlockResult) {
281        Log.showInfo(TAG, `notifyUnlockScreenResult`);
282        this.screenLockModel.sendScreenLockEvent(UNLOCK_SCREEN_RESULT, result, (error, data) => {
283            Log.showInfo(TAG, `notifyUnlockScreenResult: error:${JSON.stringify(error)} data:${JSON.stringify(data)}`);
284        });
285    }
286
287    notifyLockScreenResult(result: LockResult) {
288        Log.showInfo(TAG, `notifyLockScreenResult`);
289        this.screenLockModel.sendScreenLockEvent(LOCK_SCREEN_RESULT, result, (error, data) => {
290            Log.showInfo(TAG, `notifyLockScreenResult: error:${JSON.stringify(error)} data:${JSON.stringify(data)}`);
291        });
292    }
293
294    notifyDrawDone() {
295        Log.showInfo(TAG, `notifyDrawDone`);
296        //notify the base service that the screen is loaded
297        this.screenLockModel.sendScreenLockEvent(SCREENLOCK_DRAW_DONE, 0, (error, result) => {
298            Log.showInfo(TAG, `notifyDrawDone:  error:${JSON.stringify(error)} result:${JSON.stringify(result)}`);
299        });
300    }
301
302    authUser(authSubType: AuthSubType, passwordData: number[] | string, callback): void {
303        Log.showInfo(TAG, `authUser authSubType:${authSubType}`);
304        let password: string = '';
305        if (typeof passwordData == 'string') {
306            password = passwordData;
307        } else {
308            password = passwordData.join('');
309        }
310        this.accountModel.registerPWDInputer(password).then(() => {
311            Log.showInfo(TAG, `registerPWDInputer success`);
312            this.accountModel.authUser(CHALLENGE_INT, AuthType.PIN, AuthTurstLevel.ATL4, (result, extraInfo) => {
313                Log.showDebug(TAG, `authUser  callback:${result} extraInfo:${JSON.stringify(extraInfo)}`);
314                this.accountModel.unregisterInputer();
315                callback(result, extraInfo);
316            })
317        }).catch(() => {
318            Log.showError(TAG, `registerPWDInputer fails`);
319        })
320    }
321
322    authUserByFace() {
323        if (!mWillRecognizeFace) {
324            Log.showInfo(TAG, "Recognize face is not support")
325            return
326        }
327        Log.showInfo(TAG, `authUserByFace`);
328        this.accountModel.authUser(CHALLENGE_INT, AuthType.FACE, AuthTurstLevel.ATL1, (result, extraInfo) => {
329            Log.showDebug(TAG, `authUserByFace callback:${result} extraInfo:${JSON.stringify(extraInfo)}`);
330            if (result == 0) {
331                AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Unlock);
332                this.unlockScreen()
333            } else {
334                AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.FaceNotRecognized);
335                this.currentLockStatus = ScreenLockStatus.FaceNotRecognized;
336            }
337        })
338    }
339
340    onUserSwitch(userId: number) {
341        this.accountModel.onUserSwitch(userId)
342    }
343
344    goBack() {
345        Log.showInfo(TAG, `screen lock service goBack`);
346        Router.back();
347        this.notifyUnlockScreenResult(UnlockResult.Cancel)
348        this.accountModel.unregisterInputer();
349    }
350
351    backPage(): void {
352        if (mRouterPath != "" && this.currentLockStatus !== ScreenLockStatus.Unlock) {
353            this.goBack();
354        }
355    }
356
357    destroy() {
358        this.screenLockModel.eventCancelListener(EVENT_SYSTEM_READY);
359        this.screenLockModel.eventCancelListener(EVENT_END_SCREEN_ON);
360        this.screenLockModel.eventCancelListener(EVENT_BEGIN_SLEEP);
361        this.screenLockModel.eventCancelListener(EVENT_UNLOCK_SCREEN);
362        this.accountModel.eventCancelListener(ACTIVATING_TYPE, ACTIVATING_EVENT);
363        this.accountModel.eventCancelListener(ACTIVATE_TYPE, ACTIVATE_EVENT)
364        this.accountModel.commonEventCancelListener();
365        this.accountModel.modelFinish()
366        this.stopMonitorMemory()
367    }
368
369    setUnlockAnimation(beginAnimation: Callback<Callback<void>>) {
370        mUnLockBeginAnimation = beginAnimation;
371    }
372
373    getAuthProperty(authType, callback) {
374        Log.showInfo(TAG, `getAuthProperty param: authType ${authType}`);
375        this.accountModel.getAuthProperty(authType, (properties) => {
376            callback(properties);
377        })
378    }
379
380    private publishByUser(eventName: string, activeUserId: number) {
381        Log.showDebug(TAG, `publishByUser event name: ${eventName}, userId: ${activeUserId}`)
382        let publishData : CommonEventPublishData = {
383            parameters : {
384                userId : activeUserId
385            }
386        };
387        commonEvent.publish(eventName, publishData, (error, value) => {
388            if (error.code) {
389                Log.showError(TAG, 'Operation failed. Cause: ' + JSON.stringify(error));
390            } else {
391                Log.showDebug(TAG, 'publish common event success. ' + JSON.stringify(value));
392            }
393        });
394    }
395
396    private startMonitorMemory() {
397        this.memoryMonitor = setInterval(() => {
398            const pss = hiDebug.getPss();
399            Log.showInfo(TAG, `app pss info is: ${pss}`);
400            if (pss > MEMORY_MONITOR_LIMIT_KB) {
401                WriteFaultLog({FAULT_ID: FaultID.MEMORY, MSG: "pss over limit"})
402            }
403        }, MEMORY_MONITOR_PERIOD_MS)
404    }
405
406    private stopMonitorMemory() {
407        if (this.memoryMonitor !== -1) {
408            clearInterval(this.memoryMonitor);
409            this.memoryMonitor = -1;
410        }
411    }
412}
413
414let screenLockService = createOrGet(ScreenLockService, TAG);
415
416export default screenLockService as ScreenLockService;