• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.launcher3.util
17 
18 import android.content.Context
19 import android.content.Intent
20 import android.os.Process
21 import android.os.UserManager
22 import androidx.annotation.VisibleForTesting
23 import com.android.launcher3.dagger.ApplicationContext
24 import com.android.launcher3.dagger.LauncherAppComponent
25 import com.android.launcher3.dagger.LauncherAppSingleton
26 import com.android.launcher3.util.Executors.MAIN_EXECUTOR
27 import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
28 import javax.inject.Inject
29 
30 @LauncherAppSingleton
31 class LockedUserState
32 @Inject
33 constructor(@ApplicationContext private val context: Context, lifeCycle: DaggerSingletonTracker) {
34     val isUserUnlockedAtLauncherStartup: Boolean
35     var isUserUnlocked = false
36         private set(value) {
37             field = value
38             if (value) {
39                 notifyUserUnlocked()
40             }
41         }
42 
43     private val mUserUnlockedActions: RunnableList = RunnableList()
44 
45     @VisibleForTesting
46     val userUnlockedReceiver =
<lambda>null47         SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR) {
48             if (Intent.ACTION_USER_UNLOCKED == it.action) {
49                 isUserUnlocked = true
50             }
51         }
52 
53     init {
54         // 1) when user reboots devices, launcher process starts at lock screen and both
55         // isUserUnlocked and isUserUnlockedAtLauncherStartup are init as false. After user unlocks
56         // screen, isUserUnlocked will be updated to true via Intent.ACTION_USER_UNLOCKED,
57         // yet isUserUnlockedAtLauncherStartup will remains as false.
58         // 2) when launcher process restarts after user has unlocked screen, both variable are
59         // init as true and will not change.
60         isUserUnlocked = checkIsUserUnlocked()
61         isUserUnlockedAtLauncherStartup = isUserUnlocked
62         if (!isUserUnlocked) {
63             userUnlockedReceiver.register(
<lambda>null64                 {
65                     // If user is unlocked while registering broadcast receiver, we should update
66                     // [isUserUnlocked], which will call [notifyUserUnlocked] in setter
67                     if (checkIsUserUnlocked()) {
68                         MAIN_EXECUTOR.execute { isUserUnlocked = true }
69                     }
70                 },
71                 Intent.ACTION_USER_UNLOCKED,
72             )
73         }
<lambda>null74         lifeCycle.addCloseable { userUnlockedReceiver.unregisterReceiverSafely() }
75     }
76 
checkIsUserUnlockednull77     private fun checkIsUserUnlocked() =
78         context.getSystemService(UserManager::class.java)!!.isUserUnlocked(Process.myUserHandle())
79 
80     private fun notifyUserUnlocked() {
81         mUserUnlockedActions.executeAllAndDestroy()
82         userUnlockedReceiver.unregisterReceiverSafely()
83     }
84 
85     /**
86      * Adds a `Runnable` to be executed when a user is unlocked. If the user is already unlocked,
87      * this runnable will run immediately because RunnableList will already have been destroyed.
88      */
runOnUserUnlockednull89     fun runOnUserUnlocked(action: Runnable) {
90         mUserUnlockedActions.add(action)
91     }
92 
93     /** Removes a previously queued `Runnable` to be run when the user is unlocked. */
removeOnUserUnlockedRunnablenull94     fun removeOnUserUnlockedRunnable(action: Runnable) {
95         mUserUnlockedActions.remove(action)
96     }
97 
98     companion object {
99         @VisibleForTesting
100         @JvmField
101         val INSTANCE = DaggerSingletonObject(LauncherAppComponent::getLockedUserState)
102 
getnull103         @JvmStatic fun get(context: Context): LockedUserState = INSTANCE.get(context)
104     }
105 }
106