Add device locked API for TrustAgentService

Bug: 18414067
Change-Id: I96c68af9ccc9940acf9fab3b5bd39a3485f01045
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 89156da..68ea0aa 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -29,5 +29,6 @@
     void reportRequireCredentialEntry(int userId);
     void registerTrustListener(in ITrustListener trustListener);
     void unregisterTrustListener(in ITrustListener trustListener);
+    void reportKeyguardShowingChanged();
     boolean isDeviceLocked(int userId);
 }
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 3d262b1..705a144 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -88,6 +88,19 @@
     }
 
     /**
+     * Reports that the visibility of the keyguard has changed.
+     *
+     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+     */
+    public void reportKeyguardShowingChanged() {
+        try {
+            mService.reportKeyguardShowingChanged();
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    /**
      * Registers a listener for trust events.
      *
      * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl
index bb0c2b2..f07d0d0 100644
--- a/core/java/android/service/trust/ITrustAgentService.aidl
+++ b/core/java/android/service/trust/ITrustAgentService.aidl
@@ -25,6 +25,8 @@
 interface ITrustAgentService {
     oneway void onUnlockAttempt(boolean successful);
     oneway void onTrustTimeout();
+    oneway void onDeviceLocked();
+    oneway void onDeviceUnlocked();
     oneway void onConfigure(in List<PersistableBundle> options, IBinder token);
     oneway void setCallback(ITrustAgentServiceCallback callback);
 }
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index d6c997f..62fa978 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -92,6 +92,8 @@
     private static final int MSG_UNLOCK_ATTEMPT = 1;
     private static final int MSG_CONFIGURE = 2;
     private static final int MSG_TRUST_TIMEOUT = 3;
+    private static final int MSG_DEVICE_LOCKED = 4;
+    private static final int MSG_DEVICE_UNLOCKED = 5;
 
     /**
      * Class containing raw data for a given configuration request.
@@ -134,6 +136,12 @@
                 case MSG_TRUST_TIMEOUT:
                     onTrustTimeout();
                     break;
+                case MSG_DEVICE_LOCKED:
+                    onDeviceLocked();
+                    break;
+                case MSG_DEVICE_UNLOCKED:
+                    onDeviceUnlocked();
+                    break;
             }
         }
     };
@@ -173,6 +181,20 @@
     public void onTrustTimeout() {
     }
 
+    /**
+     * Called when the device enters a state where a PIN, pattern or
+     * password must be entered to unlock it.
+     */
+    public void onDeviceLocked() {
+    }
+
+    /**
+     * Called when the device leaves a state where a PIN, pattern or
+     * password must be entered to unlock it.
+     */
+    public void onDeviceUnlocked() {
+    }
+
     private void onError(String msg) {
         Slog.v(TAG, "Remote exception while " + msg);
     }
@@ -300,6 +322,16 @@
                     .sendToTarget();
         }
 
+        @Override
+        public void onDeviceLocked() throws RemoteException {
+            mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget();
+        }
+
+        @Override
+        public void onDeviceUnlocked() throws RemoteException {
+            mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget();
+        }
+
         @Override /* Binder API */
         public void setCallback(ITrustAgentServiceCallback callback) {
             synchronized (mLock) {
diff --git a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
index bb72c12..00193ed 100644
--- a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml
@@ -44,6 +44,12 @@
             android:paddingTop="8dp"
             android:paddingBottom="8dp"
             android:text="Report unlock attempts" />
+    <CheckBox android:id="@+id/report_device_locked"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp"
+            android:text="Report device locked or unlocked" />
 
     <LinearLayout
             android:layout_width="match_parent"
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
index f28d0e4..e6a0dd7 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
@@ -56,6 +56,7 @@
             = "preference.report_unlock_attempts";
     private static final String PREFERENCE_MANAGING_TRUST
             = "preference.managing_trust";
+    private static final String PREFERENCE_REPORT_DEVICE_LOCKED = "preference.report_device_locked";
 
     private static final String TAG = "SampleTrustAgent";
 
@@ -80,17 +81,37 @@
     @Override
     public void onTrustTimeout() {
         super.onTrustTimeout();
-        Toast.makeText(this, "onTrustTimeout(): timeout expired", Toast.LENGTH_SHORT).show();
+        logAndShowToast("onTrustTimeout(): timeout expired");
+    }
+
+    @Override
+    public void onDeviceLocked() {
+        super.onDeviceLocked();
+        if (getReportDeviceLocked(this)) {
+            logAndShowToast("onDeviceLocked(): device is now locked");
+        }
+    }
+
+    @Override
+    public void onDeviceUnlocked() {
+        super.onDeviceUnlocked();
+        if (getReportDeviceLocked(this)) {
+            logAndShowToast("onDeviceUnlocked(): device is now unlocked");
+        }
     }
 
     @Override
     public void onUnlockAttempt(boolean successful) {
         if (getReportUnlockAttempts(this)) {
-            Toast.makeText(this, "onUnlockAttempt(successful=" + successful + ")",
-                    Toast.LENGTH_SHORT).show();
+            logAndShowToast("onUnlockAttempt(successful=" + successful + ")");
         }
     }
 
+    private void logAndShowToast(String text) {
+        Log.i(TAG, text);
+        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
+    }
+
     @Override
     public boolean onConfigure(List<PersistableBundle> options) {
         if (options != null) {
@@ -125,8 +146,7 @@
                             intent.getLongExtra(EXTRA_DURATION, 0),
                             intent.getBooleanExtra(EXTRA_INITIATED_BY_USER, false));
                 } catch (IllegalStateException e) {
-                    Toast.makeText(context,
-                            "IllegalStateException: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+                    logAndShowToast("IllegalStateException: " + e.getMessage());
                 }
             } else if (ACTION_REVOKE_TRUST.equals(action)) {
                 revokeTrust();
@@ -160,6 +180,18 @@
         return sharedPreferences.getBoolean(PREFERENCE_REPORT_UNLOCK_ATTEMPTS, false);
     }
 
+    public static void setReportDeviceLocked(Context context, boolean enabled) {
+        SharedPreferences sharedPreferences = PreferenceManager
+                .getDefaultSharedPreferences(context);
+        sharedPreferences.edit().putBoolean(PREFERENCE_REPORT_DEVICE_LOCKED, enabled).apply();
+    }
+
+    public static boolean getReportDeviceLocked(Context context) {
+        SharedPreferences sharedPreferences = PreferenceManager
+                .getDefaultSharedPreferences(context);
+        return sharedPreferences.getBoolean(PREFERENCE_REPORT_DEVICE_LOCKED, false);
+    }
+
     public static void setIsManagingTrust(Context context, boolean enabled) {
         SharedPreferences sharedPreferences = PreferenceManager
                 .getDefaultSharedPreferences(context);
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
index 7edf2bb..29b15cb 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
@@ -31,6 +31,7 @@
     private static final int TRUST_DURATION_MS = 30 * 1000;
 
     private CheckBox mReportUnlockAttempts;
+    private CheckBox mReportDeviceLocked;
     private CheckBox mManagingTrust;
     private TextView mCheckDeviceLockedResult;
 
@@ -53,6 +54,9 @@
         mReportUnlockAttempts = (CheckBox) findViewById(R.id.report_unlock_attempts);
         mReportUnlockAttempts.setOnCheckedChangeListener(this);
 
+        mReportDeviceLocked = (CheckBox) findViewById(R.id.report_device_locked);
+        mReportDeviceLocked.setOnCheckedChangeListener(this);
+
         mManagingTrust = (CheckBox) findViewById(R.id.managing_trust);
         mManagingTrust.setOnCheckedChangeListener(this);
 
@@ -88,6 +92,8 @@
             SampleTrustAgent.setReportUnlockAttempts(this, isChecked);
         } else if (buttonView == mManagingTrust) {
             SampleTrustAgent.setIsManagingTrust(this, isChecked);
+        } else if (buttonView == mReportDeviceLocked) {
+            SampleTrustAgent.setReportDeviceLocked(this, isChecked);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 20e418c..5f92dc6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -23,6 +23,7 @@
 import android.app.PendingIntent;
 import android.app.SearchManager;
 import android.app.StatusBarManager;
+import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -187,8 +188,9 @@
     /** High level access to the window manager for dismissing keyguard animation */
     private IWindowManager mWM;
 
-    /** UserManager for querying number of users */
-    private UserManager mUserManager;
+
+    /** TrustManager for letting it know when we change visibility */
+    private TrustManager mTrustManager;
 
     /** SearchManager for determining whether or not search assistant is available */
     private SearchManager mSearchManager;
@@ -484,7 +486,8 @@
     private void setup() {
         mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWM = WindowManagerGlobal.getWindowManagerService();
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
+
         mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
         mShowKeyguardWakeLock.setReferenceCounted(false);
 
@@ -501,6 +504,7 @@
 
         // Assume keyguard is showing (unless it's disabled) until we know for sure...
         mShowing = !shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled();
+        mTrustManager.reportKeyguardShowingChanged();
 
         mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(mContext,
                 mViewMediatorCallback, mLockPatternUtils);
@@ -931,7 +935,7 @@
         if (mLockPatternUtils.checkVoldPassword()) {
             if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
             // Without this, settings is not enabled until the lock screen first appears
-            mShowing = false;
+            setShowing(false);
             hideLocked();
             return;
         }
@@ -1249,7 +1253,7 @@
 
             mStatusBarKeyguardViewManager.show(options);
             mHiding = false;
-            mShowing = true;
+            setShowing(true);
             resetKeyguardDonePendingLocked();
             mHideAnimationRun = false;
             updateActivityLockScreenState();
@@ -1328,7 +1332,7 @@
             }
 
             mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
-            mShowing = false;
+            setShowing(false);
             resetKeyguardDonePendingLocked();
             mHideAnimationRun = false;
             updateActivityLockScreenState();
@@ -1389,7 +1393,7 @@
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
             mStatusBarKeyguardViewManager.verifyUnlock();
-            mShowing = true;
+            setShowing(true);
             updateActivityLockScreenState();
         }
     }
@@ -1471,4 +1475,12 @@
             this.fadeoutDuration = fadeoutDuration;
         }
     }
+
+    private void setShowing(boolean showing) {
+        boolean changed = (showing != mShowing);
+        mShowing = showing;
+        if (changed) {
+            mTrustManager.reportKeyguardShowingChanged();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 4906bd1..57b204d 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -232,6 +232,12 @@
             mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
             setCallback(mCallback);
             updateDevicePolicyFeatures();
+
+            if (mTrustManagerService.isDeviceLockedInner(mUserId)) {
+                onDeviceLocked();
+            } else {
+                onDeviceUnlocked();
+            }
         }
 
         @Override
@@ -287,6 +293,7 @@
             onError(e);
         }
     }
+
     /**
      * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
      */
@@ -298,6 +305,28 @@
         }
     }
 
+    /**
+     * @see android.service.trust.TrustAgentService#onDeviceLocked()
+     */
+    public void onDeviceLocked() {
+        try {
+            if (mTrustAgentService != null) mTrustAgentService.onDeviceLocked();
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    /**
+     * @see android.service.trust.TrustAgentService#onDeviceUnlocked()
+     */
+    public void onDeviceUnlocked() {
+        try {
+            if (mTrustAgentService != null) mTrustAgentService.onDeviceUnlocked();
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
     private void setCallback(ITrustAgentServiceCallback callback) {
         try {
             if (mTrustAgentService != null) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 361f0e6..a2ea1c8 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -26,7 +26,6 @@
 
 import android.Manifest;
 import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.ITrustListener;
 import android.app.trust.ITrustManager;
@@ -61,8 +60,8 @@
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.Xml;
+import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.WindowManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -98,6 +97,10 @@
     private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3;
     private static final int MSG_ENABLED_AGENTS_CHANGED = 4;
     private static final int MSG_REQUIRE_CREDENTIAL_ENTRY = 5;
+    private static final int MSG_KEYGUARD_SHOWING_CHANGED = 6;
+    private static final int MSG_START_USER = 7;
+    private static final int MSG_CLEANUP_USER = 8;
+    private static final int MSG_SWITCH_USER = 9;
 
     private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
     private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
@@ -112,7 +115,11 @@
     @GuardedBy("mUserIsTrusted")
     private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray();
 
+    @GuardedBy("mDeviceLockedForUser")
+    private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray();
+
     private boolean mTrustAgentsCanRun = false;
+    private int mCurrentUser = UserHandle.USER_OWNER;
 
     public TrustManagerService(Context context) {
         super(context);
@@ -179,10 +186,15 @@
     public void updateTrust(int userId, boolean initiatedByUser) {
         dispatchOnTrustManagedChanged(aggregateIsTrustManaged(userId), userId);
         boolean trusted = aggregateIsTrusted(userId);
+        boolean changed;
         synchronized (mUserIsTrusted) {
+            changed = mUserIsTrusted.get(userId) != trusted;
             mUserIsTrusted.put(userId, trusted);
         }
         dispatchOnTrustChanged(trusted, userId, initiatedByUser);
+        if (changed) {
+            refreshDeviceLockedForUser(userId);
+        }
     }
 
     void refreshAgentList(int userId) {
@@ -214,8 +226,7 @@
                     || userInfo.guestToRemove) continue;
             if (!userInfo.supportsSwitchTo()) continue;
             if (!mActivityManager.isUserRunning(userInfo.id)) continue;
-            if (lockPatternUtils.getKeyguardStoredPasswordQuality(userInfo.id)
-                    == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) continue;
+            if (!lockPatternUtils.isSecure(userInfo.id)) continue;
             if (!mUserHasAuthenticatedSinceBoot.get(userInfo.id)) continue;
             DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager();
             int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id);
@@ -275,6 +286,73 @@
         }
     }
 
+    boolean isDeviceLockedInner(int userId) {
+        synchronized (mDeviceLockedForUser) {
+            return mDeviceLockedForUser.get(userId, true);
+        }
+    }
+
+    private void refreshDeviceLockedForUser(int userId) {
+        if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_OWNER) {
+            Log.e(TAG, "refreshAgentList(userId=" + userId + "): Invalid user handle,"
+                    + " must be USER_ALL or a specific user.", new Throwable("here"));
+            userId = UserHandle.USER_ALL;
+        }
+
+        List<UserInfo> userInfos;
+        if (userId == UserHandle.USER_ALL) {
+            userInfos = mUserManager.getUsers(true /* excludeDying */);
+        } else {
+            userInfos = new ArrayList<>();
+            userInfos.add(mUserManager.getUserInfo(userId));
+        }
+
+        IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+
+        for (int i = 0; i < userInfos.size(); i++) {
+            UserInfo info = userInfos.get(i);
+
+            if (info == null || info.partial || !info.isEnabled() || info.guestToRemove
+                    || !info.supportsSwitchTo()) {
+                continue;
+            }
+
+            int id = info.id;
+            boolean secure = mLockPatternUtils.isSecure(id);
+            boolean trusted = aggregateIsTrusted(id);
+            boolean showingKeyguard = true;
+            if (mCurrentUser == id) {
+                try {
+                    showingKeyguard = wm.isKeyguardLocked();
+                } catch (RemoteException e) {
+                }
+            }
+            boolean deviceLocked = secure && showingKeyguard && !trusted;
+
+            boolean changed;
+            synchronized (mDeviceLockedForUser) {
+                changed = isDeviceLockedInner(id) != deviceLocked;
+                mDeviceLockedForUser.put(id, deviceLocked);
+            }
+            if (changed) {
+                dispatchDeviceLocked(id, deviceLocked);
+            }
+        }
+    }
+
+    private void dispatchDeviceLocked(int userId, boolean isLocked) {
+        for (int i = 0; i < mActiveAgents.size(); i++) {
+            AgentInfo agent = mActiveAgents.valueAt(i);
+            if (agent.userId == userId) {
+                if (isLocked) {
+                    agent.agent.onDeviceLocked();
+                } else{
+                    agent.agent.onDeviceUnlocked();
+                }
+            }
+        }
+    }
+
     void updateDevicePolicyFeatures() {
         for (int i = 0; i < mActiveAgents.size(); i++) {
             AgentInfo info = mActiveAgents.valueAt(i);
@@ -542,12 +620,17 @@
 
     @Override
     public void onStartUser(int userId) {
-        refreshAgentList(userId);
+        mHandler.obtainMessage(MSG_START_USER, userId, 0, null).sendToTarget();
     }
 
     @Override
     public void onCleanupUser(int userId) {
-        refreshAgentList(userId);
+        mHandler.obtainMessage(MSG_CLEANUP_USER, userId, 0, null).sendToTarget();
+    }
+
+    @Override
+    public void onSwitchUser(int userId) {
+        mHandler.obtainMessage(MSG_SWITCH_USER, userId, 0, null).sendToTarget();
     }
 
     // Plumbing
@@ -580,6 +663,14 @@
         }
 
         @Override
+        public void reportKeyguardShowingChanged() throws RemoteException {
+            enforceReportPermission();
+            // coalesce refresh messages.
+            mHandler.removeMessages(MSG_KEYGUARD_SHOWING_CHANGED);
+            mHandler.sendEmptyMessage(MSG_KEYGUARD_SHOWING_CHANGED);
+        }
+
+        @Override
         public void registerTrustListener(ITrustListener trustListener) throws RemoteException {
             enforceListenerPermission();
             mHandler.obtainMessage(MSG_REGISTER_LISTENER, trustListener).sendToTarget();
@@ -597,21 +688,7 @@
                     false /* allowAll */, true /* requireFull */, "isDeviceLocked", null);
             userId = resolveProfileParent(userId);
 
-            boolean isSecure = mLockPatternUtils.isSecure(userId);
-
-            boolean isTrusted;
-            synchronized (mUserIsTrusted) {
-                isTrusted = mUserIsTrusted.get(userId);
-            }
-
-            boolean isLocked;
-            if (ActivityManager.getCurrentUser() != userId) {
-                isLocked = true;
-            } else {
-                isLocked = WindowManagerGlobal.getWindowManagerService().isKeyguardLocked();
-            }
-
-            return isSecure && isLocked && !isTrusted;
+            return isDeviceLockedInner(userId);
         }
 
         private void enforceReportPermission() {
@@ -636,19 +713,13 @@
                 fout.println("disabled because the third-party apps can't run yet.");
                 return;
             }
-            final UserInfo currentUser;
             final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
-            try {
-                currentUser = ActivityManagerNative.getDefault().getCurrentUser();
-            } catch (RemoteException e) {
-                throw new RuntimeException(e);
-            }
             mHandler.runWithScissors(new Runnable() {
                 @Override
                 public void run() {
                     fout.println("Trust manager state:");
                     for (UserInfo user : userInfos) {
-                        dumpUser(fout, user, user.id == currentUser.id);
+                        dumpUser(fout, user, user.id == mCurrentUser);
                     }
                 }
             }, 1500);
@@ -657,11 +728,17 @@
         private void dumpUser(PrintWriter fout, UserInfo user, boolean isCurrent) {
             fout.printf(" User \"%s\" (id=%d, flags=%#x)",
                     user.name, user.id, user.flags);
+            if (!user.supportsSwitchTo()) {
+                fout.println("(managed profile)");
+                fout.println("   disabled because switching to this user is not possible.");
+                return;
+            }
             if (isCurrent) {
                 fout.print(" (current)");
             }
             fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id)));
             fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id)));
+            fout.print(", deviceLocked=" + dumpBool(isDeviceLockedInner(user.id)));
             fout.println();
             fout.println("   Enabled agents:");
             boolean duplicateSimpleNames = false;
@@ -726,10 +803,23 @@
                     break;
                 case MSG_ENABLED_AGENTS_CHANGED:
                     refreshAgentList(UserHandle.USER_ALL);
+                    // This is also called when the security mode of a user changes.
+                    refreshDeviceLockedForUser(UserHandle.USER_ALL);
                     break;
                 case MSG_REQUIRE_CREDENTIAL_ENTRY:
                     requireCredentialEntry(msg.arg1);
                     break;
+                case MSG_KEYGUARD_SHOWING_CHANGED:
+                    refreshDeviceLockedForUser(UserHandle.USER_CURRENT);
+                    break;
+                case MSG_START_USER:
+                case MSG_CLEANUP_USER:
+                    refreshAgentList(msg.arg1);
+                    break;
+                case MSG_SWITCH_USER:
+                    mCurrentUser = msg.arg1;
+                    refreshDeviceLockedForUser(UserHandle.USER_ALL);
+                    break;
             }
         }
     };
@@ -771,8 +861,14 @@
                 int userId = getUserId(intent);
                 if (userId > 0) {
                     mUserHasAuthenticatedSinceBoot.delete(userId);
-                    mUserIsTrusted.delete(userId);
+                    synchronized (mUserIsTrusted) {
+                        mUserIsTrusted.delete(userId);
+                    }
+                    synchronized (mDeviceLockedForUser) {
+                        mDeviceLockedForUser.delete(userId);
+                    }
                     refreshAgentList(userId);
+                    refreshDeviceLockedForUser(userId);
                 }
             }
         }