Merge "Add explicit method to dismiss Keyguard"
diff --git a/Android.mk b/Android.mk
index 514ed47..7103f67 100644
--- a/Android.mk
+++ b/Android.mk
@@ -338,6 +338,7 @@
 	core/java/com/android/internal/backup/IObbBackupService.aidl \
 	core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \
 	core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \
+	core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl \
 	core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
 	core/java/com/android/internal/policy/IKeyguardService.aidl \
 	core/java/com/android/internal/policy/IKeyguardStateCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 6bec747..2e543e4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4824,6 +4824,7 @@
 
   public class KeyguardManager {
     method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+    method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
@@ -4833,12 +4834,19 @@
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
   }
 
+  public static abstract class KeyguardManager.KeyguardDismissCallback {
+    ctor public KeyguardManager.KeyguardDismissCallback();
+    method public void onDismissCancelled();
+    method public void onDismissError();
+    method public void onDismissSucceeded();
+  }
+
   public deprecated class KeyguardManager.KeyguardLock {
     method public void disableKeyguard();
     method public void reenableKeyguard();
   }
 
-  public static abstract interface KeyguardManager.OnKeyguardExitResult {
+  public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
     method public abstract void onKeyguardExitResult(boolean);
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 1f3fd7d..613f387 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4978,6 +4978,7 @@
 
   public class KeyguardManager {
     method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+    method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
@@ -4987,12 +4988,19 @@
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
   }
 
+  public static abstract class KeyguardManager.KeyguardDismissCallback {
+    ctor public KeyguardManager.KeyguardDismissCallback();
+    method public void onDismissCancelled();
+    method public void onDismissError();
+    method public void onDismissSucceeded();
+  }
+
   public deprecated class KeyguardManager.KeyguardLock {
     method public void disableKeyguard();
     method public void reenableKeyguard();
   }
 
-  public static abstract interface KeyguardManager.OnKeyguardExitResult {
+  public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
     method public abstract void onKeyguardExitResult(boolean);
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 4a4bf70..b321ae6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4834,6 +4834,7 @@
 
   public class KeyguardManager {
     method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+    method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
@@ -4843,12 +4844,19 @@
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
   }
 
+  public static abstract class KeyguardManager.KeyguardDismissCallback {
+    ctor public KeyguardManager.KeyguardDismissCallback();
+    method public void onDismissCancelled();
+    method public void onDismissError();
+    method public void onDismissSucceeded();
+  }
+
   public deprecated class KeyguardManager.KeyguardLock {
     method public void disableKeyguard();
     method public void reenableKeyguard();
   }
 
-  public static abstract interface KeyguardManager.OnKeyguardExitResult {
+  public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
     method public abstract void onKeyguardExitResult(boolean);
   }
 
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
index 84fb626..8defb33 100644
--- a/cmds/wm/src/com/android/commands/wm/Wm.java
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -274,7 +274,7 @@
     }
 
     private void runDismissKeyguard() throws Exception {
-        mWm.dismissKeyguard();
+        mWm.dismissKeyguard(null /* callback */);
     }
 
     private int parseDimension(String s) throws NumberFormatException {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 82be7ab..1a36d1a 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -31,6 +31,7 @@
 import android.app.ITaskStackListener;
 import android.app.IUiAutomationConnection;
 import android.app.IUidObserver;
+
 import android.app.IUserSwitchObserver;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -65,6 +66,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
 
 import java.util.List;
 
@@ -571,6 +573,7 @@
     void setPictureInPictureAspectRatio(in IBinder token, float aspectRatio);
     boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
             in IBinder activityToken);
+    void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
 
     // WARNING: when these transactions are updated, check if they are any callers on the native
     // side. If so, make sure they are using the correct transaction ids.
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 725cc29..036b47c 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -17,24 +17,32 @@
 package android.app;
 
 import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.app.trust.ITrustManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
 import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.IUserManager;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.UserHandle;
-import android.os.UserManager;
+import android.util.Log;
 import android.view.IWindowManager;
 import android.view.IOnKeyguardExitResult;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
+
 /**
  * Class that can be used to lock and unlock the keyboard. Get an instance of this
  * class by calling {@link android.content.Context#getSystemService(java.lang.String)}
@@ -43,10 +51,13 @@
  * {@link android.app.KeyguardManager.KeyguardLock}.
  */
 public class KeyguardManager {
-    private IWindowManager mWM;
-    private ITrustManager mTrustManager;
-    private IUserManager mUserManager;
-    private Context mContext;
+
+    private static final String TAG = "KeyguardManager";
+
+    private final Context mContext;
+    private final IWindowManager mWM;
+    private final IActivityManager mAm;
+    private final ITrustManager mTrustManager;
 
     /**
      * Intent used to prompt user for device credentials.
@@ -125,8 +136,8 @@
     }
 
     /**
-     * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
-     * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+     * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
+     * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
      * instead; this allows you to seamlessly hide the keyguard as your application
      * moves in and out of the foreground and does not require that any special
      * permissions be requested.
@@ -190,9 +201,11 @@
     }
 
     /**
+     * @deprecated Use {@link KeyguardDismissCallback}
      * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify
      * caller of result.
      */
+    @Deprecated
     public interface OnKeyguardExitResult {
 
         /**
@@ -202,19 +215,41 @@
         void onKeyguardExitResult(boolean success);
     }
 
+    /**
+     * Callback passed to {@link KeyguardManager#dismissKeyguard} to notify caller of result.
+     */
+    public static abstract class KeyguardDismissCallback {
+
+        /**
+         * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not
+         * available, not showing or when the activity requesting the Keyguard dismissal isn't
+         * showing or isn't showing behind Keyguard.
+         */
+        public void onDismissError() { }
+
+        /**
+         * Called when dismissing Keyguard has succeeded and the device is now unlocked.
+         */
+        public void onDismissSucceeded() { }
+
+        /**
+         * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the
+         * operation or the bouncer was hidden for some other reason.
+         */
+        public void onDismissCancelled() { }
+    }
 
     KeyguardManager(Context context) throws ServiceNotFoundException {
         mContext = context;
         mWM = WindowManagerGlobal.getWindowManagerService();
+        mAm = ActivityManager.getService();
         mTrustManager = ITrustManager.Stub.asInterface(
                 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE));
-        mUserManager = IUserManager.Stub.asInterface(
-                ServiceManager.getServiceOrThrow(Context.USER_SERVICE));
     }
 
     /**
-     * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
-     * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+     * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
+     * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
      * instead; this allows you to seamlessly hide the keyguard as your application
      * moves in and out of the foreground and does not require that any special
      * permissions be requested.
@@ -296,9 +331,8 @@
      * @hide
      */
     public boolean isDeviceLocked(int userId) {
-        ITrustManager trustManager = getTrustManager();
         try {
-            return trustManager.isDeviceLocked(userId);
+            return mTrustManager.isDeviceLocked(userId);
         } catch (RemoteException e) {
             return false;
         }
@@ -322,25 +356,63 @@
      * @hide
      */
     public boolean isDeviceSecure(int userId) {
-        ITrustManager trustManager = getTrustManager();
         try {
-            return trustManager.isDeviceSecure(userId);
+            return mTrustManager.isDeviceSecure(userId);
         } catch (RemoteException e) {
             return false;
         }
     }
 
-    private synchronized ITrustManager getTrustManager() {
-        if (mTrustManager == null) {
-            mTrustManager = ITrustManager.Stub.asInterface(
-                    ServiceManager.getService(Context.TRUST_SERVICE));
+    /**
+     * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
+     * be dismissed.
+     * <p>
+     * If the Keyguard is not secure or the device is currently in a trusted state, calling this
+     * method will immediately dismiss the Keyguard without any user interaction.
+     * <p>
+     * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
+     * UI so the user can enter their credentials.
+     *
+     * @param activity The activity requesting the dismissal. The activity must be either visible
+     *                 by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
+     *                 which it would be visible if Keyguard would not be hiding it. If that's not
+     *                 the case, the request will fail immediately and
+     *                 {@link KeyguardDismissCallback#onDismissError} will be invoked.
+     * @param callback The callback to be called if the request to dismiss Keyguard was successful
+     *                 or {@code null} if the caller isn't interested in knowing the result.
+     * @param handler The handler to invoke the callback on, or {@code null} to use the main
+     *                handler.
+     */
+    public void dismissKeyguard(@NonNull Activity activity,
+            @Nullable KeyguardDismissCallback callback, @Nullable Handler handler) {
+        try {
+            final Handler actualHandler = handler != null
+                    ? handler
+                    : new Handler(Looper.getMainLooper());
+            mAm.dismissKeyguard(activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
+                @Override
+                public void onDismissError() throws RemoteException {
+                    actualHandler.post(callback::onDismissError);
+                }
+
+                @Override
+                public void onDismissSucceeded() throws RemoteException {
+                    actualHandler.post(callback::onDismissSucceeded);
+                }
+
+                @Override
+                public void onDismissCancelled() throws RemoteException {
+                    actualHandler.post(callback::onDismissCancelled);
+                }
+            });
+        } catch (RemoteException e) {
+            Log.i(TAG, "Failed to dismiss keyguard: " + e);
         }
-        return mTrustManager;
     }
 
     /**
-     * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
-     * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+     * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
+     * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
      * instead; this allows you to seamlessly hide the keyguard as your application
      * moves in and out of the foreground and does not require that any special
      * permissions be requested.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index bccb822..bd1ad8e 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -20,6 +20,7 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 
 import android.content.res.CompatibilityInfo;
@@ -210,8 +211,7 @@
     boolean isKeyguardLocked();
     boolean isKeyguardSecure();
     boolean inKeyguardRestrictedInputMode();
-    void dismissKeyguard();
-    void keyguardGoingAway(int flags);
+    void dismissKeyguard(IKeyguardDismissCallback callback);
 
     // Requires INTERACT_ACROSS_USERS_FULL permission
     void setSwitchingUser(boolean switching);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2971280..b8408dd 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.app.KeyguardManager;
 import android.app.Presentation;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -911,16 +912,17 @@
         public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
 
         /** Window flag: when set the window will cause the keyguard to
-         * be dismissed, only if it is not a secure lock keyguard.  Because such
+         * be dismissed, only if it is not a secure lock keyguard. Because such
          * a keyguard is not needed for security, it will never re-appear if
          * the user navigates to another window (in contrast to
          * {@link #FLAG_SHOW_WHEN_LOCKED}, which will only temporarily
          * hide both secure and non-secure keyguards but ensure they reappear
          * when the user moves to another UI that doesn't hide them).
          * If the keyguard is currently active and is secure (requires an
-         * unlock pattern) than the user will still need to confirm it before
+         * unlock credential) than the user will still need to confirm it before
          * seeing this window, unless {@link #FLAG_SHOW_WHEN_LOCKED} has
          * also been set.
+         * @see KeyguardManager#dismissKeyguard
          */
         public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 82379c4..3171019 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.ActivityManager.StackId;
 import android.content.Context;
@@ -31,6 +32,7 @@
 import android.os.RemoteException;
 import android.view.animation.Animation;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 
 import java.io.PrintWriter;
@@ -1162,8 +1164,10 @@
 
     /**
      * Ask the policy to dismiss the keyguard, if it is currently shown.
+     *
+     * @param callback Callback to be informed about the result.
      */
-    public void dismissKeyguardLw();
+    public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback);
 
     /**
      * Ask the policy whether the Keyguard has drawn. If the Keyguard is disabled, this method
diff --git a/core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl b/core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl
new file mode 100644
index 0000000..635c504
--- /dev/null
+++ b/core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy;
+
+oneway interface IKeyguardDismissCallback {
+    void onDismissError();
+    void onDismissSucceeded();
+    void onDismissCancelled();
+}
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 788103d..a019ea1 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -16,6 +16,7 @@
 package com.android.internal.policy;
 
 import com.android.internal.policy.IKeyguardDrawnCallback;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardStateCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 
@@ -34,7 +35,7 @@
 
     void addStateMonitorCallback(IKeyguardStateCallback callback);
     void verifyUnlock(IKeyguardExitCallback callback);
-    void dismiss(boolean allowWhileOccluded);
+    void dismiss(IKeyguardDismissCallback callback);
     void onDreamingStarted();
     void onDreamingStopped();
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 21f68f5..e036128 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -26,6 +26,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
@@ -89,9 +90,10 @@
     }
 
     public KeyguardBouncer createKeyguardBouncer(Context context, ViewMediatorCallback callback,
-            LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
-            ViewGroup container) {
-        return new KeyguardBouncer(context, callback, lockPatternUtils, windowManager, container);
+            LockPatternUtils lockPatternUtils,
+            ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry) {
+        return new KeyguardBouncer(context, callback, lockPatternUtils, container,
+                dismissCallbackRegistry);
     }
 
     public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
new file mode 100644
index 0000000..262d29d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+import java.util.ArrayList;
+
+/**
+ * Registry holding the current set of {@link IKeyguardDismissCallback}s.
+ */
+public class DismissCallbackRegistry {
+
+    private final ArrayList<DismissCallbackWrapper> mDismissCallbacks = new ArrayList<>();
+
+    public void addCallback(IKeyguardDismissCallback callback) {
+        mDismissCallbacks.add(new DismissCallbackWrapper(callback));
+    }
+
+    public void notifyDismissCancelled() {
+        for (int i = mDismissCallbacks.size() - 1; i >= 0; i--) {
+            mDismissCallbacks.get(i).notifyDismissCancelled();
+        }
+        mDismissCallbacks.clear();
+    }
+
+    public void notifyDismissSucceeded() {
+        for (int i = mDismissCallbacks.size() - 1; i >= 0; i--) {
+            mDismissCallbacks.get(i).notifyDismissSucceeded();
+        }
+        mDismissCallbacks.clear();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackWrapper.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackWrapper.java
new file mode 100644
index 0000000..8a91144
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackWrapper.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+/**
+ * A light wrapper around {@link IKeyguardDismissCallback} handling {@link RemoteException}s.
+ */
+public class DismissCallbackWrapper {
+
+    private static final String TAG = "DismissCallbackWrapper";
+
+    private IKeyguardDismissCallback mCallback;
+
+    public DismissCallbackWrapper(IKeyguardDismissCallback callback) {
+        mCallback = callback;
+    }
+
+    public void notifyDismissError() {
+        try {
+            mCallback.onDismissError();
+        } catch (RemoteException e) {
+            Log.i(TAG, "Failed to call callback", e);
+        }
+    }
+
+    public void notifyDismissCancelled() {
+        try {
+            mCallback.onDismissCancelled();
+        } catch (RemoteException e) {
+            Log.i(TAG, "Failed to call callback", e);
+        }
+    }
+
+    public void notifyDismissSucceeded() {
+        try {
+            mCallback.onDismissSucceeded();
+        } catch (RemoteException e) {
+            Log.i(TAG, "Failed to call callback", e);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index fe9f55f..3532f41 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -26,6 +26,7 @@
 import android.os.Trace;
 import android.util.Log;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
@@ -89,9 +90,9 @@
         }
 
         @Override // Binder interface
-        public void dismiss(boolean allowWhileOccluded) {
+        public void dismiss(IKeyguardDismissCallback callback) {
             checkPermission();
-            mKeyguardViewMediator.dismiss(allowWhileOccluded);
+            mKeyguardViewMediator.dismiss(callback);
         }
 
         @Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index de327bb..2192b8c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -26,7 +26,6 @@
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
-import android.app.SearchManager;
 import android.app.StatusBarManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
@@ -49,20 +48,18 @@
 import android.os.Trace;
 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;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
-import android.view.IWindowManager;
 import android.view.ViewGroup;
-import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardStateCallback;
@@ -253,6 +250,7 @@
      * var being non-null as an indicator that there is an in progress request.
      */
     private IKeyguardExitCallback mExitSecureCallback;
+    private final DismissCallbackRegistry mDismissCallbackRegistry = new DismissCallbackRegistry();
 
     // the properties of the keyguard
 
@@ -348,7 +346,7 @@
                 UserInfo info = UserManager.get(mContext).getUserInfo(userId);
                 if (info != null && (info.isGuest() || info.isDemo())) {
                     // If we just switched to a guest, try to dismiss keyguard.
-                    dismiss(false /* allowWhileOccluded */);
+                    dismiss(null /* callback */);
                 }
             }
         }
@@ -516,7 +514,7 @@
                 return;
             }
 
-            tryKeyguardDone(true);
+            tryKeyguardDone();
             if (strongAuth) {
                 mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
             }
@@ -566,10 +564,7 @@
             Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#readyForKeyguardDone");
             if (mKeyguardDonePending) {
                 mKeyguardDonePending = false;
-
-                // Somebody has called keyguardDonePending before, which means that we are
-                // authenticated
-                tryKeyguardDone(true);
+                tryKeyguardDone();
             }
             Trace.endSection();
         }
@@ -1253,16 +1248,21 @@
 
     /**
      * Dismiss the keyguard through the security layers.
-     * @param allowWhileOccluded if true, dismiss the keyguard even if it's currently occluded.
+     * @param callback Callback to be informed about the result
      */
-    public void handleDismiss(boolean allowWhileOccluded) {
-        if (mShowing && (allowWhileOccluded || !mOccluded)) {
+    private void handleDismiss(IKeyguardDismissCallback callback) {
+        if (mShowing) {
+            if (callback != null) {
+                mDismissCallbackRegistry.addCallback(callback);
+            }
             mStatusBarKeyguardViewManager.dismissAndCollapse();
+        } else if (callback != null) {
+            new DismissCallbackWrapper(callback).notifyDismissError();
         }
     }
 
-    public void dismiss(boolean allowWhileOccluded) {
-        mHandler.obtainMessage(DISMISS, allowWhileOccluded ? 1 : 0, 0).sendToTarget();
+    public void dismiss(IKeyguardDismissCallback callback) {
+        mHandler.obtainMessage(DISMISS, callback).sendToTarget();
     }
 
     /**
@@ -1395,12 +1395,12 @@
         }
     };
 
-    public void keyguardDone(boolean authenticated) {
+    public void keyguardDone() {
         Trace.beginSection("KeyguardViewMediator#keyguardDone");
-        if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated +")");
+        if (DEBUG) Log.d(TAG, "keyguardDone()");
         userActivity();
         EventLog.writeEvent(70000, 2);
-        Message msg = mHandler.obtainMessage(KEYGUARD_DONE, authenticated ? 1 : 0);
+        Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
         mHandler.sendMessage(msg);
         Trace.endSection();
     }
@@ -1456,7 +1456,7 @@
                     break;
                 case KEYGUARD_DONE:
                     Trace.beginSection("KeyguardViewMediator#handleMessage KEYGUARD_DONE");
-                    handleKeyguardDone(msg.arg1 != 0);
+                    handleKeyguardDone();
                     Trace.endSection();
                     break;
                 case KEYGUARD_DONE_DRAWING:
@@ -1475,7 +1475,7 @@
                     }
                     break;
                 case DISMISS:
-                    handleDismiss(msg.arg1 == 1 ? true : false /* allowWhileOccluded */);
+                    handleDismiss((IKeyguardDismissCallback) msg.obj);
                     break;
                 case START_KEYGUARD_EXIT_ANIM:
                     Trace.beginSection("KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
@@ -1493,9 +1493,9 @@
         }
     };
 
-    private void tryKeyguardDone(boolean authenticated) {
+    private void tryKeyguardDone() {
         if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
-            handleKeyguardDone(authenticated);
+            handleKeyguardDone();
         } else if (!mHideAnimationRun) {
             mHideAnimationRun = true;
             mHideAnimationRunning = true;
@@ -1507,7 +1507,7 @@
      * @see #keyguardDone
      * @see #KEYGUARD_DONE
      */
-    private void handleKeyguardDone(boolean authenticated) {
+    private void handleKeyguardDone() {
         Trace.beginSection("KeyguardViewMediator#handleKeyguardDone");
         final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
         if (mLockPatternUtils.isSecure(currentUser)) {
@@ -1518,9 +1518,7 @@
             resetKeyguardDonePendingLocked();
         }
 
-        if (authenticated) {
-            mUpdateMonitor.clearFailedUnlockAttempts();
-        }
+        mUpdateMonitor.clearFailedUnlockAttempts();
         mUpdateMonitor.clearFingerprintRecognized();
 
         if (mGoingToSleep) {
@@ -1529,22 +1527,21 @@
         }
         if (mExitSecureCallback != null) {
             try {
-                mExitSecureCallback.onKeyguardExitResult(authenticated);
+                mExitSecureCallback.onKeyguardExitResult(true /* authenciated */);
             } catch (RemoteException e) {
-                Slog.w(TAG, "Failed to call onKeyguardExitResult(" + authenticated + ")", e);
+                Slog.w(TAG, "Failed to call onKeyguardExitResult()", e);
             }
 
             mExitSecureCallback = null;
 
-            if (authenticated) {
-                // after succesfully exiting securely, no need to reshow
-                // the keyguard when they've released the lock
-                mExternallyEnabled = true;
-                mNeedToReshowWhenReenabled = false;
-                updateInputRestricted();
-            }
+            // after succesfully exiting securely, no need to reshow
+            // the keyguard when they've released the lock
+            mExternallyEnabled = true;
+            mNeedToReshowWhenReenabled = false;
+            updateInputRestricted();
         }
 
+        mDismissCallbackRegistry.notifyDismissSucceeded();
         handleHide();
         Trace.endSection();
     }
@@ -1691,7 +1688,7 @@
 
     private final Runnable mHideAnimationFinishedRunnable = () -> {
         mHideAnimationRunning = false;
-        tryKeyguardDone(true);
+        tryKeyguardDone();
     };
 
     /**
@@ -1913,7 +1910,7 @@
     public void onWakeAndUnlocking() {
         Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
         mWakeAndUnlocking = true;
-        keyguardDone(true /* authenticated */);
+        keyguardDone();
         Trace.endSection();
     }
 
@@ -1922,7 +1919,8 @@
             ScrimController scrimController,
             FingerprintUnlockController fingerprintUnlockController) {
         mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
-                statusBarWindowManager, scrimController, fingerprintUnlockController);
+                statusBarWindowManager, scrimController, fingerprintUnlockController,
+                mDismissCallbackRegistry);
         return mStatusBarKeyguardViewManager;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 34b8371..2124011 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -37,6 +37,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -48,17 +49,17 @@
 
     final static private String TAG = "KeyguardBouncer";
 
-    protected Context mContext;
-    protected ViewMediatorCallback mCallback;
-    protected LockPatternUtils mLockPatternUtils;
-    protected ViewGroup mContainer;
-    private StatusBarWindowManager mWindowManager;
+    protected final Context mContext;
+    protected final ViewMediatorCallback mCallback;
+    protected final LockPatternUtils mLockPatternUtils;
+    protected final ViewGroup mContainer;
+    private final FalsingManager mFalsingManager;
+    private final DismissCallbackRegistry mDismissCallbackRegistry;
     protected KeyguardHostView mKeyguardView;
     protected ViewGroup mRoot;
     private boolean mShowingSoon;
     private int mBouncerPromptReason;
-    private FalsingManager mFalsingManager;
-    private KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
+    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
                 public void onStrongAuthStateChanged(int userId) {
@@ -67,15 +68,15 @@
             };
 
     public KeyguardBouncer(Context context, ViewMediatorCallback callback,
-            LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
-            ViewGroup container) {
+            LockPatternUtils lockPatternUtils, ViewGroup container,
+            DismissCallbackRegistry dismissCallbackRegistry) {
         mContext = context;
         mCallback = callback;
         mLockPatternUtils = lockPatternUtils;
         mContainer = container;
-        mWindowManager = windowManager;
         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
         mFalsingManager = FalsingManager.getInstance(mContext);
+        mDismissCallbackRegistry = dismissCallbackRegistry;
     }
 
     public void show(boolean resetSecuritySelection) {
@@ -169,6 +170,9 @@
     }
 
     public void hide(boolean destroyView) {
+        if (isShowing()) {
+            mDismissCallbackRegistry.notifyDismissCancelled();
+        }
         mFalsingManager.onBouncerHidden();
         cancelShowRunnable();
         if (mKeyguardView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 69decd7..a82ffb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -33,6 +33,7 @@
 import com.android.systemui.DejankUtils;
 import com.android.keyguard.LatencyTracker;
 import com.android.systemui.SystemUIFactory;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.RemoteInputController;
 
@@ -102,14 +103,15 @@
     public void registerStatusBar(PhoneStatusBar phoneStatusBar,
             ViewGroup container, StatusBarWindowManager statusBarWindowManager,
             ScrimController scrimController,
-            FingerprintUnlockController fingerprintUnlockController) {
+            FingerprintUnlockController fingerprintUnlockController,
+            DismissCallbackRegistry dismissCallbackRegistry) {
         mPhoneStatusBar = phoneStatusBar;
         mContainer = container;
         mStatusBarWindowManager = statusBarWindowManager;
         mScrimController = scrimController;
         mFingerprintUnlockController = fingerprintUnlockController;
         mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
-                mViewMediatorCallback, mLockPatternUtils, mStatusBarWindowManager, container);
+                mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index fafbdd1..0396613 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -92,20 +92,6 @@
         return mCanSkipBouncer;
     }
 
-    public void unlock() {
-        try {
-            WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
-        } catch (RemoteException e) {
-        }
-    }
-
-    public void lock() {
-        try {
-            WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */);
-        } catch (RemoteException e) {
-        }
-    }
-
     public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) {
         if (mShowing == showing && mSecure == secure && mOccluded == occluded) return;
         mShowing = showing;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
new file mode 100644
index 0000000..131a70b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * runtest systemui -c com.android.systemui.keyguard.DismissCallbackRegistryTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DismissCallbackRegistryTest {
+
+    private final DismissCallbackRegistry mDismissCallbackRegistry = new DismissCallbackRegistry();
+    private @Mock IKeyguardDismissCallback mMockCallback;
+    private @Mock IKeyguardDismissCallback mMockCallback2;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testCancelled() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.notifyDismissCancelled();
+        verify(mMockCallback).onDismissCancelled();
+    }
+
+    @Test
+    public void testCancelled_multiple() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.addCallback(mMockCallback2);
+        mDismissCallbackRegistry.notifyDismissCancelled();
+        verify(mMockCallback).onDismissCancelled();
+        verify(mMockCallback2).onDismissCancelled();
+    }
+
+    @Test
+    public void testSucceeded() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.notifyDismissSucceeded();
+        verify(mMockCallback).onDismissSucceeded();
+    }
+
+    @Test
+    public void testSucceeded_multiple() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.addCallback(mMockCallback2);
+        mDismissCallbackRegistry.notifyDismissSucceeded();
+        verify(mMockCallback).onDismissSucceeded();
+        verify(mMockCallback2).onDismissSucceeded();
+    }
+
+    @Test
+    public void testOnlyOnce() throws Exception {
+        mDismissCallbackRegistry.addCallback(mMockCallback);
+        mDismissCallbackRegistry.notifyDismissSucceeded();
+        mDismissCallbackRegistry.notifyDismissSucceeded();
+        verify(mMockCallback, times(1)).onDismissSucceeded();
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c8ed872..d085a47 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -23,6 +23,8 @@
 import android.app.WaitResult;
 import android.graphics.PointF;
 import android.os.IDeviceIdentifiersPolicyService;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.telephony.TelephonyIntents;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -22542,6 +22544,17 @@
         return rInfo != null && rInfo.activityInfo != null;
     }
 
+    @Override
+    public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback)
+            throws RemoteException {
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            mKeyguardController.dismissKeyguard(token, callback);
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
     /**
      * Attach an agent to the specified process (proces name or PID)
      */
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 90b46ed..214a357 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -207,6 +207,8 @@
     boolean keysPaused;     // has key dispatching been paused for it?
     int launchMode;         // the launch mode activity attribute.
     boolean visible;        // does this activity's window need to be shown?
+    boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
+                                     // might hide this activity?
     boolean sleeping;       // have we told the activity to sleep?
     boolean nowVisible;     // is this activity's window visible?
     boolean idle;           // has the activity gone idle?
@@ -1248,9 +1250,15 @@
         mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
     }
 
-    /** Return true if the input activity should be made visible */
-    boolean shouldBeVisible(boolean behindTranslucentActivity, boolean stackVisibleBehind,
-            ActivityRecord visibleBehind, boolean behindFullscreenActivity) {
+    /**
+     * @return true if the input activity should be made visible, ignoring any effect Keyguard
+     * might have on the visibility
+     *
+     * @see {@link ActivityStack#checkKeyguardVisibility}
+     */
+    boolean shouldBeVisibleIgnoringKeyguard(boolean behindTranslucentActivity,
+            boolean stackVisibleBehind, ActivityRecord visibleBehind,
+            boolean behindFullscreenActivity) {
         if (!okToShowLocked()) {
             return false;
         }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 473b1a3..005b8aa 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1660,13 +1660,15 @@
                     aboveTop = false;
 
                     // Check whether activity should be visible without Keyguard influence
-                    final boolean shouldBeVisible = r.shouldBeVisible(behindTranslucentActivity,
-                            stackVisibleBehind, visibleBehind, behindFullscreenActivity);
+                    final boolean visibleIgnoringKeyguard = r.shouldBeVisibleIgnoringKeyguard(
+                            behindTranslucentActivity, stackVisibleBehind, visibleBehind,
+                            behindFullscreenActivity);
+                    r.visibleIgnoringKeyguard = visibleIgnoringKeyguard;
 
                     // Now check whether it's really visible depending on Keyguard state.
-                    final boolean reallyVisible = checkKeyguardVisibility(r, shouldBeVisible,
-                            isTop);
-                    if (shouldBeVisible) {
+                    final boolean reallyVisible = checkKeyguardVisibility(r,
+                            visibleIgnoringKeyguard, isTop);
+                    if (visibleIgnoringKeyguard) {
                         behindFullscreenActivity = updateBehindFullscreen(stackInvisible,
                                 behindFullscreenActivity, task, r);
                         if (behindFullscreenActivity && !r.fullscreen) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 2d92f00..eb34669 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4076,7 +4076,7 @@
                                     Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
                             if (mLockTaskModeState == LOCK_TASK_MODE_PINNED && shouldLockKeyguard) {
                                 mWindowManager.lockNow(null);
-                                mWindowManager.dismissKeyguard();
+                                mWindowManager.dismissKeyguard(null /* callback */);
                                 new LockPatternUtils(mService.mContext)
                                         .requireCredentialEntry(UserHandle.USER_ALL);
                             }
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 9d8c383..5e02597 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -20,6 +20,8 @@
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
@@ -29,6 +31,11 @@
 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.PrintWriter;
@@ -42,6 +49,8 @@
  */
 class KeyguardController {
 
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
+
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
     private WindowManagerService mWindowManager;
@@ -108,7 +117,6 @@
                 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
                         false /* alwaysKeepCurrent */, convertTransitFlags(flags),
                         false /* forceOverride */);
-                mWindowManager.keyguardGoingAway(flags);
                 mService.updateSleepIfNeededLocked();
 
                 // Some stack visibility might change (e.g. docked stack)
@@ -122,6 +130,23 @@
         }
     }
 
+    void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
+        final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
+        if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
+            failCallback(callback);
+            return;
+        }
+        mWindowManager.dismissKeyguard(callback);
+    }
+
+    private void failCallback(IKeyguardDismissCallback callback) {
+        try {
+            callback.onDismissError();
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to call callback", e);
+        }
+    }
+
     private int convertTransitFlags(int keyguardGoingAwayFlags) {
         int result = 0;
         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
@@ -215,7 +240,7 @@
      */
     private void handleDismissKeyguard() {
         if (mDismissingKeyguardActivity != null) {
-            mWindowManager.dismissKeyguard();
+            mWindowManager.dismissKeyguard(null /* callback */);
 
             // If we are about to unocclude the Keyguard, but we can dismiss it without security,
             // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ccdda13..f48db05 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -216,6 +216,7 @@
 
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.policy.PhoneWindow;
 import com.android.internal.statusbar.IStatusBarService;
@@ -6631,12 +6632,18 @@
     }
 
     @Override
-    public void dismissKeyguardLw() {
+    public void dismissKeyguardLw(IKeyguardDismissCallback callback) {
         if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
             if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.dismissKeyguardLw");
 
             // ask the keyguard to prompt the user to authenticate if necessary
-            mKeyguardDelegate.dismiss(true /* allowWhileOccluded */);
+            mKeyguardDelegate.dismiss(callback);
+        } else if (callback != null) {
+            try {
+                callback.onDismissError();
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to call callback", e);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index f37f987..1b4eaf5 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -15,6 +15,7 @@
 import android.util.Slog;
 import android.view.WindowManagerPolicy.OnKeyguardExitResult;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
@@ -244,9 +245,9 @@
         mKeyguardState.occluded = isOccluded;
     }
 
-    public void dismiss(boolean allowWhileOccluded) {
+    public void dismiss(IKeyguardDismissCallback callback) {
         if (mKeyguardService != null) {
-            mKeyguardService.dismiss(allowWhileOccluded);
+            mKeyguardService.dismiss(callback);
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index c4a0dd3..0b839b8 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -22,6 +22,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
@@ -73,9 +74,9 @@
     }
 
     @Override // Binder interface
-    public void dismiss(boolean allowWhileOccluded) {
+    public void dismiss(IKeyguardDismissCallback callback) {
         try {
-            mService.dismiss(allowWhileOccluded);
+            mService.dismiss(callback);
         } catch (RemoteException e) {
             Slog.w(TAG , "Remote Exception", e);
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9b089ec..f51b6a0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import android.Manifest;
+import android.Manifest.permission;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -125,6 +126,7 @@
 import com.android.internal.R;
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputContext;
@@ -3935,20 +3937,13 @@
     }
 
     @Override
-    public void dismissKeyguard() {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
-        }
+    public void dismissKeyguard(IKeyguardDismissCallback callback) {
+        checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard");
         synchronized(mWindowMap) {
-            mPolicy.dismissKeyguardLw();
+            mPolicy.dismissKeyguardLw(callback);
         }
     }
 
-    @Override
-    public void keyguardGoingAway(int flags) {
-    }
-
     public void onKeyguardOccludedChanged(boolean occluded) {
         synchronized (mWindowMap) {
             mPolicy.onKeyguardOccludedChangedLw(occluded);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index ed4c79f..1853a65 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -16,9 +16,11 @@
 
 package com.android.server.wm;
 
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.server.input.InputManagerService;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -528,8 +530,7 @@
     }
 
     @Override
-    public void dismissKeyguardLw() {
-
+    public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback) {
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 4596210..a0ded87 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -20,6 +20,7 @@
 import android.graphics.Rect;
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -516,11 +517,7 @@
     }
 
     @Override
-    public void dismissKeyguard() {
-    }
-
-    @Override
-    public void keyguardGoingAway(int flags) throws RemoteException {
+    public void dismissKeyguard(IKeyguardDismissCallback callback) throws RemoteException {
     }
 
     @Override