Merge "Create work challenge timeout"
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 2c12317..23e4d97 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -248,8 +248,9 @@
      * @hide
      */
     public boolean isDeviceLocked(int userId) {
+        ITrustManager trustManager = getTrustManager();
         try {
-            return mTrustManager.isDeviceLocked(userId);
+            return trustManager.isDeviceLocked(userId);
         } catch (RemoteException e) {
             return false;
         }
@@ -273,13 +274,22 @@
      * @hide
      */
     public boolean isDeviceSecure(int userId) {
+        ITrustManager trustManager = getTrustManager();
         try {
-            return mTrustManager.isDeviceSecure(userId);
+            return trustManager.isDeviceSecure(userId);
         } catch (RemoteException e) {
             return false;
         }
     }
 
+    private synchronized ITrustManager getTrustManager() {
+        if (mTrustManager == null) {
+            mTrustManager = ITrustManager.Stub.asInterface(
+                    ServiceManager.getService(Context.TRUST_SERVICE));
+        }
+        return mTrustManager;
+    }
+
     /**
      * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
      * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 2dea545..a3fe6ab 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -29,6 +29,7 @@
     void registerTrustListener(in ITrustListener trustListener);
     void unregisterTrustListener(in ITrustListener trustListener);
     void reportKeyguardShowingChanged();
+    void setDeviceLockedForUser(int userId, boolean locked);
     boolean isDeviceLocked(int userId);
     boolean isDeviceSecure(int userId);
 }
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index aff69f0..ee591d3 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -51,6 +51,21 @@
     }
 
     /**
+     * Changes the lock status for the given user. This is only applicable to Managed Profiles,
+     * other users should be handled by Keyguard.
+     *
+     * @param userId The id for the user to be locked/unlocked.
+     * @param locked The value for that user's locked state.
+     */
+    public void setDeviceLockedForUser(int userId, boolean locked) {
+        try {
+            mService.setDeviceLockedForUser(userId, locked);
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    /**
      * Reports that user {@param userId} has tried to unlock the device.
      *
      * @param successful if true, the unlock attempt was successful.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index eee685f..f7d0b71 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -32,6 +32,7 @@
 import android.content.pm.UserInfo;
 import android.media.AudioManager;
 import android.media.SoundPool;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.DeadObjectException;
 import android.os.Handler;
@@ -43,6 +44,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -135,6 +137,8 @@
 
     private static final String DELAYED_KEYGUARD_ACTION =
         "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD";
+    private static final String DELAYED_LOCK_PROFILE_ACTION =
+            "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_LOCK";
 
     // used for handler messages
     private static final int SHOW = 2;
@@ -322,6 +326,8 @@
     private boolean mWakeAndUnlocking;
     private IKeyguardDrawnCallback mDrawnCallback;
 
+    private boolean mIsPerUserLock;
+
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
@@ -565,6 +571,8 @@
         mShowKeyguardWakeLock.setReferenceCounted(false);
 
         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));
+        mContext.registerReceiver(
+                mBroadcastReceiver, new IntentFilter(DELAYED_LOCK_PROFILE_ACTION));
 
         mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);
 
@@ -637,6 +645,7 @@
             doKeyguardLocked(null);
             mUpdateMonitor.registerCallback(mUpdateCallback);
         }
+        mIsPerUserLock = StorageManager.isFileBasedEncryptionEnabled();
         // Most services aren't available until the system reaches the ready state, so we
         // send it here when the device first boots.
         maybeSendUserPresentBroadcast();
@@ -660,7 +669,7 @@
             final boolean lockImmediately =
                     mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser)
                             || !mLockPatternUtils.isSecure(currentUser);
-            long timeout = getLockTimeout();
+            long timeout = getLockTimeout(KeyguardUpdateMonitor.getCurrentUser());
 
             if (mExitSecureCallback != null) {
                 if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");
@@ -710,10 +719,11 @@
                 mPendingLock = false;
             }
         }
+        doKeyguardLaterLockedForChildProfiles();
         KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);
     }
 
-    private long getLockTimeout() {
+    private long getLockTimeout(int userId) {
         // if the screen turned off because of timeout or the user hit the power button
         // and we don't need to lock immediately, set an alarm
         // to enable it a little bit later (i.e, give the user a chance
@@ -721,10 +731,6 @@
         // having to unlock the screen)
         final ContentResolver cr = mContext.getContentResolver();
 
-        // From DisplaySettings
-        long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
-                KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT);
-
         // From SecuritySettings
         final long lockAfterTimeout = Settings.Secure.getInt(cr,
                 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
@@ -732,21 +738,28 @@
 
         // From DevicePolicyAdmin
         final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
-                .getMaximumTimeToLock(null, KeyguardUpdateMonitor.getCurrentUser());
+                .getMaximumTimeToLock(null, userId);
 
         long timeout;
-        if (policyTimeout > 0) {
+
+        UserInfo user = UserManager.get(mContext).getUserInfo(userId);
+        if ((!user.isManagedProfile() && StorageManager.isFileBasedEncryptionEnabled())
+                || policyTimeout <= 0) {
+            timeout = lockAfterTimeout;
+        } else {
+            // From DisplaySettings
+            long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT,
+                    KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT);
+
             // policy in effect. Make sure we don't go beyond policy limit.
             displayTimeout = Math.max(displayTimeout, 0); // ignore negative values
             timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout);
-        } else {
-            timeout = lockAfterTimeout;
         }
         return timeout;
     }
 
     private void doKeyguardLaterLocked() {
-        long timeout = getLockTimeout();
+        long timeout = getLockTimeout(KeyguardUpdateMonitor.getCurrentUser());
         if (timeout == 0) {
             doKeyguardLocked(null);
         } else {
@@ -764,6 +777,25 @@
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
         if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
                          + mDelayedShowingSequence);
+        doKeyguardLaterLockedForChildProfiles();
+    }
+    
+    private void doKeyguardLaterLockedForChildProfiles() {
+        UserManager um = UserManager.get(mContext);
+        List<UserInfo> profiles = um.getEnabledProfiles(UserHandle.myUserId());
+        if (StorageManager.isFileBasedEncryptionEnabled() && profiles.size() > 1) {
+            for (UserInfo info : profiles) {
+                if (info.id != UserHandle.myUserId() && info.isManagedProfile()) {
+                    long userTimeout = getLockTimeout(info.id);
+                    long userWhen = SystemClock.elapsedRealtime() + userTimeout;
+                    Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
+                    lockIntent.putExtra(Intent.EXTRA_USER_ID, info.id);
+                    PendingIntent lockSender = PendingIntent.getBroadcast(
+                            mContext, 0, lockIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, userWhen, lockSender);
+                }
+            }
+        }
     }
 
     private void cancelDoKeyguardLaterLocked() {
@@ -1099,6 +1131,10 @@
         showLocked(options);
     }
 
+    private void lockProfile(int userId) {
+        mTrustManager.setDeviceLockedForUser(userId, true);
+    }
+
     private boolean shouldWaitForProvisioning() {
         return !mUpdateMonitor.isDeviceProvisioned() && !isSecure();
     }
@@ -1213,8 +1249,13 @@
                 if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
                         + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence);
                 synchronized (KeyguardViewMediator.this) {
-                    if (mDelayedShowingSequence == sequence) {
-                        doKeyguardLocked(null);
+                    doKeyguardLocked(null);
+                }
+            } else if (DELAYED_LOCK_PROFILE_ACTION.equals(intent.getAction())) {
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, 0);
+                if (userId != 0) {
+                    synchronized (KeyguardViewMediator.this) {
+                        lockProfile(userId);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index d6c6f13..6e7ace5 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -21,6 +21,8 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.backup.BackupManager;
 import android.app.trust.IStrongAuthTracker;
+import android.app.trust.ITrustManager;
+import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -38,6 +40,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -675,6 +678,12 @@
             // credential has matched
             unlockKeystore(credential, userId);
             unlockUser(userId, null);
+            UserInfo info = UserManager.get(mContext).getUserInfo(userId);
+            if (StorageManager.isFileBasedEncryptionEnabled() && info.isManagedProfile()) {
+                TrustManager trustManager =
+                        (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
+                trustManager.setDeviceLockedForUser(userId, false);
+            }
             if (shouldReEnroll) {
                 credentialUtil.setCredential(credential, credential, userId);
             }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e9e02c1..5d60c07 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -67,6 +67,7 @@
 import android.app.ResultInfo;
 import android.app.StatusBarManager;
 import android.app.admin.IDevicePolicyManager;
+import android.app.trust.ITrustManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IIntentSender;
@@ -1669,11 +1670,11 @@
         }
 
         UserInfo user = getUserInfo(userId);
-        // TODO: Timeout for work challenge
-        if (user.isManagedProfile() && StorageManager.isFileBasedEncryptionEnabled()) {
-            KeyguardManager km = (KeyguardManager) mService.mContext
-                    .getSystemService(Context.KEYGUARD_SERVICE);
-
+        KeyguardManager km = (KeyguardManager) mService.mContext
+                .getSystemService(Context.KEYGUARD_SERVICE);
+        if (user.isManagedProfile()
+                && StorageManager.isFileBasedEncryptionEnabled()
+                && km.isDeviceLocked(userId)) {
             IIntentSender target = mService.getIntentSenderLocked(
                     ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                     Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index f9d29ac..f4869fc 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -53,6 +53,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.service.trust.TrustAgentService;
 import android.util.ArraySet;
@@ -102,6 +103,7 @@
     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 static final int MSG_SET_DEVICE_LOCKED = 10;
 
     private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
     private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
@@ -288,6 +290,19 @@
         }
     }
 
+    public void setDeviceLockedForUser(int userId, boolean locked) {
+        if (StorageManager.isFileBasedEncryptionEnabled()) {
+            UserInfo info = mUserManager.getUserInfo(userId);
+            if (info.isManagedProfile()) {
+                synchronized (mDeviceLockedForUser) {
+                    mDeviceLockedForUser.put(userId, locked);
+                }
+            } else {
+                Log.wtf(TAG, "Requested to change lock state for non-profile user " + userId);
+            }
+        }
+    }
+
     boolean isDeviceLockedInner(int userId) {
         synchronized (mDeviceLockedForUser) {
             return mDeviceLockedForUser.get(userId, true);
@@ -655,7 +670,9 @@
         public boolean isDeviceLocked(int userId) throws RemoteException {
             userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                     false /* allowAll */, true /* requireFull */, "isDeviceLocked", null);
-            userId = resolveProfileParent(userId);
+            if (!StorageManager.isFileBasedEncryptionEnabled()) {
+                userId = resolveProfileParent(userId);
+            }
 
             return isDeviceLockedInner(userId);
         }
@@ -762,6 +779,12 @@
         private String dumpHex(int i) {
             return "0x" + Integer.toHexString(i);
         }
+
+        @Override
+        public void setDeviceLockedForUser(int userId, boolean value) {
+            mHandler.obtainMessage(MSG_SET_DEVICE_LOCKED, value ? 1 : 0, userId)
+                    .sendToTarget();
+        }
     };
 
     private int resolveProfileParent(int userId) {
@@ -806,6 +829,9 @@
                     mCurrentUser = msg.arg1;
                     refreshDeviceLockedForUser(UserHandle.USER_ALL);
                     break;
+                case MSG_SET_DEVICE_LOCKED:
+                    setDeviceLockedForUser(msg.arg2, msg.arg1 != 0);
+                    break;
             }
         }
     };