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 24 class LockedUserState(private val mContext: Context) : SafeCloseable { 25 val isUserUnlockedAtLauncherStartup: Boolean 26 var isUserUnlocked: Boolean 27 private set 28 private val mUserUnlockedActions: RunnableList = RunnableList() 29 30 @VisibleForTesting <lambda>null31 val mUserUnlockedReceiver = SimpleBroadcastReceiver { 32 if (Intent.ACTION_USER_UNLOCKED == it.action) { 33 isUserUnlocked = true 34 notifyUserUnlocked() 35 } 36 } 37 38 init { 39 // 1) when user reboots devices, launcher process starts at lock screen and both 40 // isUserUnlocked and isUserUnlockedAtLauncherStartup are init as false. After user unlocks 41 // screen, isUserUnlocked will be updated to true via Intent.ACTION_USER_UNLOCKED, 42 // yet isUserUnlockedAtLauncherStartup will remains as false. 43 // 2) when launcher process restarts after user has unlocked screen, both variable are 44 // init as true and will not change. 45 isUserUnlocked = 46 mContext 47 .getSystemService(UserManager::class.java)!! 48 .isUserUnlocked(Process.myUserHandle()) 49 isUserUnlockedAtLauncherStartup = isUserUnlocked 50 if (isUserUnlocked) { 51 notifyUserUnlocked() 52 } else { 53 mUserUnlockedReceiver.register(mContext, Intent.ACTION_USER_UNLOCKED) 54 } 55 } 56 notifyUserUnlockednull57 private fun notifyUserUnlocked() { 58 mUserUnlockedActions.executeAllAndDestroy() 59 Executors.THREAD_POOL_EXECUTOR.execute { 60 mUserUnlockedReceiver.unregisterReceiverSafely(mContext) 61 } 62 } 63 64 /** Stops the receiver from listening for ACTION_USER_UNLOCK broadcasts. */ closenull65 override fun close() { 66 Executors.THREAD_POOL_EXECUTOR.execute { 67 mUserUnlockedReceiver.unregisterReceiverSafely(mContext) 68 } 69 } 70 71 /** 72 * Adds a `Runnable` to be executed when a user is unlocked. If the user is already unlocked, 73 * this runnable will run immediately because RunnableList will already have been destroyed. 74 */ runOnUserUnlockednull75 fun runOnUserUnlocked(action: Runnable) { 76 mUserUnlockedActions.add(action) 77 } 78 79 companion object { 80 @VisibleForTesting 81 @JvmField <lambda>null82 val INSTANCE = MainThreadInitializedObject { LockedUserState(it) } 83 getnull84 @JvmStatic fun get(context: Context): LockedUserState = INSTANCE.get(context) 85 } 86 } 87