diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index d24675c671884..fb1392504965c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -29,8 +29,11 @@ import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE; import static android.os.BatteryManager.EXTRA_PLUGGED; import static android.os.BatteryManager.EXTRA_STATUS; +import android.annotation.AnyThread; +import android.annotation.MainThread; import android.app.ActivityManager; import android.app.AlarmManager; +import android.app.Instrumentation; import android.app.PendingIntent; import android.app.UserSwitchObserver; import android.app.admin.DevicePolicyManager; @@ -44,7 +47,6 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.ContentObserver; -import android.graphics.Bitmap; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; @@ -77,6 +79,7 @@ import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.util.Preconditions; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -355,6 +358,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private static int sCurrentUser; private Runnable mUpdateFingerprintListeningState = this::updateFingerprintListeningState; + private static boolean sDisableHandlerCheckForTesting; public synchronized static void setCurrentUser(int currentUser) { sCurrentUser = currentUser; @@ -366,6 +370,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { @Override public void onTrustChanged(boolean enabled, int userId, int flags) { + checkIsHandlerThread(); mUserHasTrust.put(userId, enabled); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -383,7 +388,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { dispatchErrorMessage(message); } - protected void handleSimSubscriptionInfoChanged() { + private void handleSimSubscriptionInfoChanged() { if (DEBUG_SIM_STATES) { Log.v(TAG, "onSubscriptionInfoChanged()"); List sil = mSubscriptionManager.getActiveSubscriptionInfoList(); @@ -451,6 +456,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { @Override public void onTrustManagedChanged(boolean managed, int userId) { + checkIsHandlerThread(); mUserTrustIsManaged.put(userId, managed); for (int i = 0; i < mCallbacks.size(); i++) { @@ -638,6 +644,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } private void notifyFingerprintRunningStateChanged() { + checkIsHandlerThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -646,6 +653,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } private void handleFaceUnlockStateChanged(boolean running, int userId) { + checkIsHandlerThread(); mUserFaceUnlockRunning.put(userId, running); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -705,6 +713,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } private void notifyStrongAuthStateChanged(int userId) { + checkIsHandlerThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1125,20 +1134,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { updateFingerprintListeningState(); } - /** - * IMPORTANT: Must be called from UI thread. - */ - public void dispatchSetBackground(Bitmap bmp) { - if (DEBUG) Log.d(TAG, "dispatchSetBackground"); - final int count = mCallbacks.size(); - for (int i = 0; i < count; i++) { - KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); - if (cb != null) { - cb.onSetBackground(bmp); - } - } - } - private void handleUserInfoChanged(int userId) { for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1350,6 +1345,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * @param hasLockscreenWallpaper Whether Keyguard has a lockscreen wallpaper. */ public void setHasLockscreenWallpaper(boolean hasLockscreenWallpaper) { + checkIsHandlerThread(); if (hasLockscreenWallpaper != mHasLockscreenWallpaper) { mHasLockscreenWallpaper = hasLockscreenWallpaper; for (int i = mCallbacks.size() - 1; i >= 0; i--) { @@ -1371,7 +1367,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { /** * Handle {@link #MSG_DPM_STATE_CHANGED} */ - protected void handleDevicePolicyManagerStateChanged() { + private void handleDevicePolicyManagerStateChanged() { updateFingerprintListeningState(); for (int i = mCallbacks.size() - 1; i >= 0; i--) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1384,7 +1380,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { /** * Handle {@link #MSG_USER_SWITCHING} */ - protected void handleUserSwitching(int userId, IRemoteCallback reply) { + private void handleUserSwitching(int userId, IRemoteCallback reply) { for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1400,7 +1396,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { /** * Handle {@link #MSG_USER_SWITCH_COMPLETE} */ - protected void handleUserSwitchComplete(int userId) { + private void handleUserSwitchComplete(int userId) { for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1422,7 +1418,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { /** * Handle {@link #MSG_BOOT_COMPLETED} */ - protected void handleBootCompleted() { + private void handleBootCompleted() { if (mBootCompleted) return; mBootCompleted = true; for (int i = 0; i < mCallbacks.size(); i++) { @@ -1444,7 +1440,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { /** * Handle {@link #MSG_DEVICE_PROVISIONED} */ - protected void handleDeviceProvisioned() { + private void handleDeviceProvisioned() { for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1461,7 +1457,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { /** * Handle {@link #MSG_PHONE_STATE_CHANGED} */ - protected void handlePhoneStateChanged(String newState) { + private void handlePhoneStateChanged(String newState) { if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) { mPhoneState = TelephonyManager.CALL_STATE_IDLE; @@ -1481,7 +1477,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { /** * Handle {@link #MSG_RINGER_MODE_CHANGED} */ - protected void handleRingerModeChange(int mode) { + private void handleRingerModeChange(int mode) { if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); mRingMode = mode; for (int i = 0; i < mCallbacks.size(); i++) { @@ -1526,8 +1522,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * Handle {@link #MSG_SIM_STATE_CHANGE} */ @VisibleForTesting - protected void handleSimStateChange(int subId, int slotId, State state) { - + void handleSimStateChange(int subId, int slotId, State state) { + checkIsHandlerThread(); if (DEBUG_SIM_STATES) { Log.d(TAG, "handleSimStateChange(subId=" + subId + ", slotId=" + slotId + ", state=" + state +")"); @@ -1590,6 +1586,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { *

Needs to be called from the main thread. */ public void onKeyguardVisibilityChanged(boolean showing) { + checkIsHandlerThread(); if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")"); mKeyguardIsVisible = showing; for (int i = 0; i < mCallbacks.size(); i++) { @@ -1680,6 +1677,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * @param callback The callback to remove */ public void removeCallback(KeyguardUpdateMonitorCallback callback) { + checkIsHandlerThread(); if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback); for (int i = mCallbacks.size() - 1; i >= 0; i--) { if (mCallbacks.get(i).get() == callback) { @@ -1694,6 +1692,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * @param callback The callback to register */ public void registerCallback(KeyguardUpdateMonitorCallback callback) { + checkIsHandlerThread(); if (DEBUG) Log.v(TAG, "*** register callback for " + callback); // Prevent adding duplicate callbacks for (int i = 0; i < mCallbacks.size(); i++) { @@ -1712,6 +1711,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { return mSwitchingUser; } + @AnyThread public void setSwitchingUser(boolean switching) { mSwitchingUser = switching; // Since this comes in on a binder thread, we need to post if first @@ -1755,6 +1755,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * NOTE: Because handleSimStateChange() invokes callbacks immediately without going * through mHandler, this *must* be called from the UI thread. */ + @MainThread public void reportSimUnlocked(int subId) { if (DEBUG_SIM_STATES) Log.v(TAG, "reportSimUnlocked(subId=" + subId + ")"); int slotId = SubscriptionManager.getSlotIndex(subId); @@ -1773,6 +1774,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { if (!bypassHandler) { mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget(); } else { + checkIsHandlerThread(); handleReportEmergencyCallAction(); } } @@ -1975,6 +1977,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } private void updateLogoutEnabled() { + checkIsHandlerThread(); boolean logoutEnabled = mDevicePolicyManager.isLogoutEnabled(); if (mLogoutEnabled != logoutEnabled) { mLogoutEnabled = logoutEnabled; @@ -1987,6 +1990,36 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } + private void checkIsHandlerThread() { + if (sDisableHandlerCheckForTesting) { + return; + } + if (!mHandler.getLooper().isCurrentThread()) { + Log.wtf(TAG, "must call on mHandler's thread " + + mHandler.getLooper().getThread() + ", not " + Thread.currentThread()); + } + } + + /** + * Turn off the handler check for testing. + * + * This is necessary because currently tests are not too careful about which thread they call + * into this class on. + * + * Note that this must be called before scheduling any work involving KeyguardUpdateMonitor + * instances. + * + * TODO: fix the tests and remove this. + */ + @VisibleForTesting + public static void disableHandlerCheckForTesting(Instrumentation instrumentation) { + Preconditions.checkNotNull(instrumentation, "Must only call this method in tests!"); + // Don't need synchronization here *if* the callers follow the contract and call this only + // before scheduling work for KeyguardUpdateMonitor on other threads, because the scheduling + // of that work forces a happens-before relationship. + sDisableHandlerCheckForTesting = true; + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("KeyguardUpdateMonitor state:"); pw.println(" SIM States:"); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index ca92d3570ff7a..6809e76c18e38 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -165,6 +165,7 @@ public class KeyguardViewMediator extends SystemUI { private static final int NOTIFY_SCREEN_TURNED_ON = 15; private static final int NOTIFY_SCREEN_TURNED_OFF = 16; private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17; + private static final int SYSTEM_READY = 18; /** * The default amount of time we stay awake (used for all key input) @@ -775,6 +776,10 @@ public class KeyguardViewMediator extends SystemUI { * Let us know that the system is ready after startup. */ public void onSystemReady() { + mHandler.obtainMessage(SYSTEM_READY).sendToTarget(); + } + + private void handleSystemReady() { synchronized (this) { if (DEBUG) Log.d(TAG, "onSystemReady"); mSystemReady = true; @@ -1603,6 +1608,9 @@ public class KeyguardViewMediator extends SystemUI { Log.w(TAG, "Timeout while waiting for activity drawn!"); Trace.endSection(); break; + case SYSTEM_READY: + handleSystemReady(); + break; } } }; diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index 7475cd7e1e360..a35ca46833e79 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -28,6 +28,8 @@ import android.testing.DexmakerShareClassLoaderRule; import android.testing.LeakCheck; import android.util.Log; +import com.android.keyguard.KeyguardUpdateMonitor; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -70,6 +72,7 @@ public abstract class SysuiTestCase { "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext"); }); InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments()); + KeyguardUpdateMonitor.disableHandlerCheckForTesting(inst); } @After