Merge "Fix activity start over Keyguard" into oc-dr1-dev
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 6ede55d..76d9823 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -346,7 +346,10 @@
 
         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
-        return createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(intent);
+        WifiTracker tracker =
+                createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(intent);
+        assertThat(tracker.isConnected()).isTrue();
+        return tracker;
     }
 
     private void waitForHandlersToProcessCurrentlyEnqueuedMessages(WifiTracker tracker)
@@ -860,23 +863,26 @@
         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
         tracker.mReceiver.onReceive(mContext, intent);
 
+        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
         verify(mockWifiListener, times(1)).onConnectedChanged();
     }
 
     @Test
-    public void onConnectedChangedCallback_shouldNBeInvokedWhenStateChanges() throws Exception {
+    public void onConnectedChangedCallback_shouldBeInvokedWhenStateChanges() throws Exception {
         WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
         verify(mockWifiListener, times(1)).onConnectedChanged();
 
         NetworkInfo networkInfo = new NetworkInfo(
                 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
         networkInfo.setDetailedState(
-                NetworkInfo.DetailedState.DISCONNECTED, "dicconnected", "test");
+                NetworkInfo.DetailedState.DISCONNECTED, "disconnected", "test");
 
         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
         tracker.mReceiver.onReceive(mContext, intent);
 
+        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
+        assertThat(tracker.isConnected()).isFalse();
         verify(mockWifiListener, times(2)).onConnectedChanged();
     }
 }
diff --git a/packages/SystemUI/res-keyguard/drawable-hdpi/ic_done_wht.png b/packages/SystemUI/res-keyguard/drawable-hdpi/ic_done_wht.png
deleted file mode 100644
index 82c01ef..0000000
--- a/packages/SystemUI/res-keyguard/drawable-hdpi/ic_done_wht.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-mdpi/ic_done_wht.png b/packages/SystemUI/res-keyguard/drawable-mdpi/ic_done_wht.png
deleted file mode 100644
index 8c16930..0000000
--- a/packages/SystemUI/res-keyguard/drawable-mdpi/ic_done_wht.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xhdpi/ic_done_wht.png b/packages/SystemUI/res-keyguard/drawable-xhdpi/ic_done_wht.png
deleted file mode 100644
index 6a4d8a7..0000000
--- a/packages/SystemUI/res-keyguard/drawable-xhdpi/ic_done_wht.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxhdpi/ic_done_wht.png b/packages/SystemUI/res-keyguard/drawable-xxhdpi/ic_done_wht.png
deleted file mode 100644
index 4c04ba2..0000000
--- a/packages/SystemUI/res-keyguard/drawable-xxhdpi/ic_done_wht.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/ic_done_wht.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/ic_done_wht.png
deleted file mode 100644
index bd6c4df..0000000
--- a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/ic_done_wht.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml
deleted file mode 100644
index 1e4022e..0000000
--- a/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:autoMirrored="true"
-        android:height="24dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-
-    <path
-        android:fillColor="#ffffffff"
-        android:pathData="M44.0,6.0L14.0,6.0c-1.4,0.0 -2.5,0.7 -3.2,1.8L0.0,24.0l10.8,16.2c0.7,1.1 1.8,1.8 3.2,1.8l30.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L48.0,10.0C48.0,7.8 46.2,6.0 44.0,6.0zM38.0,31.2L35.2,34.0L28.0,26.8L20.8,34.0L18.0,31.2l7.2,-7.2L18.0,16.8l2.8,-2.8l7.2,7.2l7.2,-7.2l2.8,2.8L30.8,24.0L38.0,31.2z"/>
-</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_backspace_black_24dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_backspace_black_24dp.xml
new file mode 100644
index 0000000..6edae4b
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/ic_backspace_black_24dp.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M22,3H7C6.31,3 5.77,3.35 5.41,3.88l-5.04,7.57c-0.22,0.34 -0.22,0.77 0,1.11l5.04,7.56C5.77,20.64 6.31,21 7,21h15c1.1,0 2,-0.9 2,-2V5C24,3.9 23.1,3 22,3zM18.3,16.3L18.3,16.3c-0.39,0.39 -1.02,0.39 -1.41,0L14,13.41l-2.89,2.89c-0.39,0.39 -1.02,0.39 -1.41,0h0c-0.39,-0.39 -0.39,-1.02 0,-1.41L12.59,12L9.7,9.11c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0L14,10.59l2.89,-2.89c0.39,-0.39 1.02,-0.39 1.41,0v0c0.39,0.39 0.39,1.02 0,1.41L15.41,12l2.89,2.89C18.68,15.27 18.68,15.91 18.3,16.3z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_done_black_24dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_done_black_24dp.xml
new file mode 100644
index 0000000..5026f07
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/ic_done_black_24dp.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M9,16.2l-3.5,-3.5a0.984,0.984 0,0 0,-1.4 0,0.984 0.984,0 0,0 0,1.4l4.19,4.19c0.39,0.39 1.02,0.39 1.41,0L20.3,7.7a0.984,0.984 0,0 0,0 -1.4,0.984 0.984,0 0,0 -1.4,0L9,16.2z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 3283e04..631cc0d 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -62,7 +62,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:gravity="center_vertical"
-                    android:src="@drawable/ic_backspace_24dp"
+                    android:src="@drawable/ic_backspace_black_24dp"
                     android:clickable="true"
                     android:paddingTop="8dip"
                     android:paddingBottom="8dip"
@@ -73,6 +73,7 @@
                     android:layout_alignEnd="@+id/pinEntry"
                     android:layout_alignParentRight="true"
                     android:tint="@color/pin_delete_color"
+                    android:tintMode="src_in"
                     />
             <View
                     android:id="@+id/divider"
@@ -204,7 +205,7 @@
                     android:layout_height="match_parent"
                     android:layout_weight="1"
                     android:paddingBottom="11sp"
-                    android:src="@drawable/ic_done_wht"
+                    android:src="@drawable/ic_done_black_24dp"
                     style="@style/Keyguard.ImageButton.NumPadEnter"
                     android:background="@drawable/ripple_drawable"
                     android:contentDescription="@string/keyboardview_keycode_enter"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index cf87f90..97c8965 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -75,7 +75,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:gravity="center_vertical"
-                    android:src="@drawable/ic_backspace_24dp"
+                    android:src="@drawable/ic_backspace_black_24dp"
                     android:clickable="true"
                     android:paddingTop="8dip"
                     android:paddingBottom="8dip"
@@ -86,6 +86,7 @@
                     android:layout_alignEnd="@+id/pinEntry"
                     android:layout_alignParentRight="true"
                     android:tint="@color/pin_delete_color"
+                    android:tintMode="src_in"
                     />
             <View
                     android:id="@+id/divider"
@@ -213,7 +214,7 @@
                     android:layout_height="match_parent"
                     android:layout_weight="1"
                     android:paddingBottom="11sp"
-                    android:src="@drawable/ic_done_wht"
+                    android:src="@drawable/ic_done_black_24dp"
                     style="@style/Keyguard.ImageButton.NumPadEnter"
                     android:background="@drawable/ripple_drawable"
                     android:contentDescription="@string/keyboardview_keycode_enter"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index 3cae493..d4c5d74 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -76,7 +76,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:gravity="center_vertical"
-                    android:src="@drawable/ic_backspace_24dp"
+                    android:src="@drawable/ic_backspace_black_24dp"
                     android:clickable="true"
                     android:paddingTop="8dip"
                     android:paddingBottom="8dip"
@@ -87,6 +87,7 @@
                     android:layout_alignEnd="@+id/pinEntry"
                     android:layout_alignParentRight="true"
                     android:tint="@color/pin_delete_color"
+                    android:tintMode="src_in"
                     />
             <View
                     android:id="@+id/divider"
@@ -214,7 +215,7 @@
                     android:layout_height="match_parent"
                     android:layout_weight="1"
                     android:paddingBottom="11sp"
-                    android:src="@drawable/ic_done_wht"
+                    android:src="@drawable/ic_done_black_24dp"
                     style="@style/Keyguard.ImageButton.NumPadEnter"
                     android:background="@drawable/ripple_drawable"
                     android:contentDescription="@string/keyboardview_keycode_enter"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 054d520..f72f379 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -116,11 +116,11 @@
     <color name="segmented_buttons_background">#14FFFFFF</color><!-- 8% white -->
 
     <color name="dark_mode_icon_color_single_tone">#99000000</color>
-    <color name="dark_mode_icon_color_dual_tone_background">#4d000000</color>
+    <color name="dark_mode_icon_color_dual_tone_background">#3d000000</color>
     <color name="dark_mode_icon_color_dual_tone_fill">#7a000000</color>
 
     <color name="light_mode_icon_color_single_tone">#ffffff</color>
-    <color name="light_mode_icon_color_dual_tone_background">#5dffffff</color>
+    <color name="light_mode_icon_color_dual_tone_background">#4dffffff</color>
     <color name="light_mode_icon_color_dual_tone_fill">#ffffff</color>
 
     <color name="volume_settings_icon_color">#7fffffff</color>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index fdfd8e8..cb96dea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -187,8 +187,12 @@
             Trace.endSection();
             return;
         }
+        startWakeAndUnlock(calculateMode());
+    }
+
+    public void startWakeAndUnlock(int mode) {
         boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
-        mMode = calculateMode();
+        mMode = mode;
         mHasScreenTurnedOnSinceAuthenticating = false;
         if (mMode == MODE_WAKE_AND_UNLOCK_PULSING && pulsingOrAod()) {
             // If we are waking the device up while we are pulsing the clock and the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
index 8bc6563..004a604 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
@@ -15,7 +15,9 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.support.annotation.VisibleForTesting;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
@@ -42,8 +44,13 @@
     private View mTouchingChild;
 
     public NearestTouchFrame(Context context, AttributeSet attrs) {
+        this(context, attrs, context.getResources().getConfiguration());
+    }
+
+    @VisibleForTesting
+    NearestTouchFrame(Context context, AttributeSet attrs, Configuration c) {
         super(context, attrs);
-        mIsActive = context.getResources().getConfiguration().smallestScreenWidthDp < 600;
+        mIsActive = c.smallestScreenWidthDp < 600;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 8dc4b38..68caab1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -142,6 +142,7 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.logging.MetricsLogger;
@@ -748,7 +749,7 @@
     private SysuiColorExtractor mColorExtractor;
     private ForegroundServiceController mForegroundServiceController;
     private ScreenLifecycle mScreenLifecycle;
-    private WakefulnessLifecycle mWakefulnessLifecycle;
+    @VisibleForTesting WakefulnessLifecycle mWakefulnessLifecycle;
 
     private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
         final int N = array.size();
@@ -3776,6 +3777,15 @@
 
     private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
             boolean afterKeyguardGone) {
+        if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP
+                && mUnlockMethodCache.canSkipBouncer()
+                && !mLeaveOpenOnKeyguardHide
+                && isPulsing()) {
+            // Reuse the fingerprint wake-and-unlock transition if we dismiss keyguard from a pulse.
+            // TODO: Factor this transition out of FingerprintUnlockController.
+            mFingerprintUnlockController.startWakeAndUnlock(
+                    FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
+        }
         if (mStatusBarKeyguardViewManager.isShowing()) {
             mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
                     afterKeyguardGone);
@@ -4212,6 +4222,8 @@
 
     public void showKeyguard() {
         mKeyguardRequested = true;
+        mLeaveOpenOnKeyguardHide = false;
+        mPendingRemoteInputView = null;
         updateIsKeyguard();
         mAssistManager.onLockscreenShown();
     }
@@ -4262,13 +4274,11 @@
         }
         updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
         updatePanelExpansionForKeyguard();
-        mLeaveOpenOnKeyguardHide = false;
         if (mDraggedDownRow != null) {
             mDraggedDownRow.setUserLocked(false);
             mDraggedDownRow.notifyHeightChanged(false  /* needsAnimation */);
             mDraggedDownRow = null;
         }
-        mPendingRemoteInputView = null;
     }
 
     private void updatePanelExpansionForKeyguard() {
@@ -4408,15 +4418,19 @@
         setBarState(StatusBarState.SHADE);
         View viewToClick = null;
         if (mLeaveOpenOnKeyguardHide) {
-            mLeaveOpenOnKeyguardHide = false;
+            if (!mKeyguardRequested) {
+                mLeaveOpenOnKeyguardHide = false;
+            }
             long delay = calculateGoingToFullShadeDelay();
             mNotificationPanel.animateToFullShade(delay);
             if (mDraggedDownRow != null) {
                 mDraggedDownRow.setUserLocked(false);
                 mDraggedDownRow = null;
             }
-            viewToClick = mPendingRemoteInputView;
-            mPendingRemoteInputView = null;
+            if (!mKeyguardRequested) {
+                viewToClick = mPendingRemoteInputView;
+                mPendingRemoteInputView = null;
+            }
 
             // Disable layout transitions in navbar for this transition because the load is just
             // too heavy for the CPU and GPU on any device.
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 acf4278..3913254 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -156,7 +156,6 @@
      */
     protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
         if (mBouncer.needsFullscreenBouncer() && !mDozing) {
-
             // The keyguard might be showing (already). So we need to hide it.
             mStatusBar.hideKeyguard();
             mBouncer.show(true /* resetSecuritySelection */);
@@ -167,6 +166,7 @@
                 mBouncer.prepare();
             }
         }
+        updateStates();
     }
 
     private void showBouncer() {
@@ -201,7 +201,7 @@
      */
     public void reset(boolean hideBouncerWhenShowing) {
         if (mShowing) {
-            if (mOccluded) {
+            if (mOccluded && !mDozing) {
                 mStatusBar.hideKeyguard();
                 mStatusBar.stopWaitingForKeyguardExit();
                 mBouncer.hide(false /* destroyView */);
@@ -250,7 +250,9 @@
     public void setDozing(boolean dozing) {
         if (mDozing != dozing) {
             mDozing = dozing;
-            reset(dozing /* hideBouncerWhenShowing */);
+            if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) {
+                reset(dozing /* hideBouncerWhenShowing */);
+            }
             updateStates();
         }
     }
@@ -292,9 +294,12 @@
         }
         mStatusBarWindowManager.setKeyguardOccluded(occluded);
 
-        // If Keyguard is reshown, don't hide the bouncer as it might just have been requested by
-        // a FLAG_DISMISS_KEYGUARD_ACTIVITY.
-        reset(false /* hideBouncerWhenShowing*/);
+        // setDozing(false) will call reset once we stop dozing.
+        if (!mDozing) {
+            // If Keyguard is reshown, don't hide the bouncer as it might just have been requested
+            // by a FLAG_DISMISS_KEYGUARD_ACTIVITY.
+            reset(false /* hideBouncerWhenShowing*/);
+        }
         if (animate && !occluded && mShowing) {
             mStatusBar.animateKeyguardUnoccluding();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
index a1cabff..5790ba3 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
@@ -28,6 +28,7 @@
 import android.os.MemoryFile;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import java.util.List;
@@ -46,7 +47,7 @@
     private final SensorManager mInner;
     private final List<Sensor> mSensorCache;
     private final HandlerThread mHandlerThread = new HandlerThread("async_sensor");
-    private final Handler mHandler;
+    @VisibleForTesting final Handler mHandler;
 
     public AsyncSensorManager(SensorManager inner) {
         mInner = inner;
@@ -150,6 +151,12 @@
 
     @Override
     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
-        mHandler.post(() -> mInner.unregisterListener(listener, sensor));
+        mHandler.post(() -> {
+            if (sensor == null) {
+                mInner.unregisterListener(listener);
+            } else {
+                mInner.unregisterListener(listener, sensor);
+            }
+        });
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
index 577dc52..ed1491d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
@@ -18,10 +18,12 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.res.Configuration;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
@@ -43,7 +45,29 @@
 
     @Before
     public void setup() {
-        mNearestTouchFrame = new NearestTouchFrame(mContext, null);
+        Configuration c = new Configuration(mContext.getResources().getConfiguration());
+        c.smallestScreenWidthDp = 500;
+        mNearestTouchFrame = new NearestTouchFrame(mContext, null, c);
+    }
+
+    @Test
+    public void testNoActionOnLargeDevices() {
+        Configuration c = new Configuration(mContext.getResources().getConfiguration());
+        c.smallestScreenWidthDp = 700;
+        mNearestTouchFrame = new NearestTouchFrame(mContext, null, c);
+
+        View left = mockViewAt(0, 0, 10, 10);
+        View right = mockViewAt(20, 0, 10, 10);
+
+        mNearestTouchFrame.addView(left);
+        mNearestTouchFrame.addView(right);
+        mNearestTouchFrame.onMeasure(0, 0);
+
+        MotionEvent ev = MotionEvent.obtain(0, 0, 0,
+                12 /* x */, 5 /* y */, 0);
+        mNearestTouchFrame.onTouchEvent(ev);
+        verify(left, never()).onTouchEvent(eq(ev));
+        ev.recycle();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index c33897e..a706368 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -65,6 +65,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.keyguard.KeyguardHostView.OnDismissAction;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.CommandQueue;
@@ -500,6 +501,14 @@
             mSystemServicesProxy = ssp;
             mNotificationPanel = panelView;
             mBarService = barService;
+            mWakefulnessLifecycle = createAwakeWakefulnessLifecycle();
+        }
+
+        private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
+            WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle();
+            wakefulnessLifecycle.dispatchStartedWakingUp();
+            wakefulnessLifecycle.dispatchFinishedWakingUp();
+            return wakefulnessLifecycle;
         }
 
         public void setBarStateForTest(int state) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java
new file mode 100644
index 0000000..469bdc0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.utils.hardware.FakeSensorManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class AsyncSensorManagerTest extends SysuiTestCase {
+
+    private TestableAsyncSensorManager mAsyncSensorManager;
+    private FakeSensorManager mFakeSensorManager;
+    private SensorEventListener mListener;
+    private FakeSensorManager.MockProximitySensor mSensor;
+
+    @Before
+    public void setUp() throws Exception {
+        mFakeSensorManager = new FakeSensorManager(mContext);
+        mAsyncSensorManager = new TestableAsyncSensorManager(mFakeSensorManager);
+        mSensor = mFakeSensorManager.getMockProximitySensor();
+        mListener = mock(SensorEventListener.class);
+    }
+
+    @Test
+    public void registerListenerImpl() throws Exception {
+        mAsyncSensorManager.registerListener(mListener, mSensor.getSensor(), 100);
+
+        mAsyncSensorManager.waitUntilRequestsCompleted();
+
+        // Verify listener was registered.
+        mSensor.sendProximityResult(true);
+        verify(mListener).onSensorChanged(any());
+    }
+
+    @Test
+    public void unregisterListenerImpl_withNullSensor() throws Exception {
+        mAsyncSensorManager.registerListener(mListener, mSensor.getSensor(), 100);
+        mAsyncSensorManager.unregisterListener(mListener);
+
+        mAsyncSensorManager.waitUntilRequestsCompleted();
+
+        // Verify listener was unregistered.
+        mSensor.sendProximityResult(true);
+        verifyNoMoreInteractions(mListener);
+    }
+
+    @Test
+    public void unregisterListenerImpl_withSensor() throws Exception {
+        mAsyncSensorManager.registerListener(mListener, mSensor.getSensor(), 100);
+        mAsyncSensorManager.unregisterListener(mListener, mSensor.getSensor());
+
+        mAsyncSensorManager.waitUntilRequestsCompleted();
+
+        // Verify listener was unregistered.
+        mSensor.sendProximityResult(true);
+        verifyNoMoreInteractions(mListener);
+    }
+
+    private class TestableAsyncSensorManager extends AsyncSensorManager {
+        public TestableAsyncSensorManager(SensorManager sensorManager) {
+            super(sensorManager);
+        }
+
+        public void waitUntilRequestsCompleted() {
+            assertTrue(mHandler.runWithScissors(() -> {}, 0));
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6afd69d..ae78d7c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -496,6 +496,7 @@
     volatile boolean mEndCallKeyHandled;
     volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
     volatile boolean mGoingToSleep;
+    volatile boolean mRequestedOrGoingToSleep;
     volatile boolean mRecentsVisible;
     volatile boolean mPictureInPictureVisible;
     // Written by vr manager thread, only read in this class.
@@ -1274,7 +1275,7 @@
         if (gestureService != null) {
             gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
                     mTmpBoolean);
-            if (mTmpBoolean.value && mGoingToSleep) {
+            if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
                 mCameraGestureTriggeredDuringGoingToSleep = true;
             }
         }
@@ -1402,17 +1403,14 @@
                 case SHORT_PRESS_POWER_NOTHING:
                     break;
                 case SHORT_PRESS_POWER_GO_TO_SLEEP:
-                    mPowerManager.goToSleep(eventTime,
-                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                    goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                     break;
                 case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
-                    mPowerManager.goToSleep(eventTime,
-                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+                    goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
                             PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
                     break;
                 case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
-                    mPowerManager.goToSleep(eventTime,
-                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+                    goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
                             PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
                     launchHomeFromHotKey();
                     break;
@@ -1437,6 +1435,11 @@
         }
     }
 
+    private void goToSleep(long eventTime, int reason, int flags) {
+        mRequestedOrGoingToSleep = true;
+        mPowerManager.goToSleep(eventTime, reason, flags);
+    }
+
     private void shortPressPowerGoHome() {
         launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/);
         if (isKeyguardShowingAndNotOccluded()) {
@@ -1469,8 +1472,7 @@
                             Settings.Global.THEATER_MODE_ON, 1);
 
                     if (mGoToSleepOnButtonPressTheaterMode && interactive) {
-                        mPowerManager.goToSleep(eventTime,
-                                PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                        goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                     }
                 }
                 break;
@@ -1553,8 +1555,7 @@
             case SHORT_PRESS_SLEEP_GO_TO_SLEEP:
             case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
                 Slog.i(TAG, "sleepRelease() calling goToSleep(GO_TO_SLEEP_REASON_SLEEP_BUTTON)");
-                mPowerManager.goToSleep(eventTime,
-                       PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
+                goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
                 break;
         }
     }
@@ -6060,7 +6061,7 @@
                             }
                             if ((mEndcallBehavior
                                     & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
-                                mPowerManager.goToSleep(event.getEventTime(),
+                                goToSleep(event.getEventTime(),
                                         PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                                 isWakeKey = false;
                             }
@@ -6569,8 +6570,10 @@
     @Override
     public void startedGoingToSleep(int why) {
         if (DEBUG_WAKEUP) Slog.i(TAG, "Started going to sleep... (why=" + why + ")");
-        mCameraGestureTriggeredDuringGoingToSleep = false;
+
         mGoingToSleep = true;
+        mRequestedOrGoingToSleep = true;
+
         if (mKeyguardDelegate != null) {
             mKeyguardDelegate.onStartedGoingToSleep(why);
         }
@@ -6584,6 +6587,7 @@
         MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
 
         mGoingToSleep = false;
+        mRequestedOrGoingToSleep = false;
 
         // We must get this work done here because the power manager will drop
         // the wake lock and let the system suspend once this function returns.
@@ -7498,8 +7502,7 @@
 
     private void applyLidSwitchState() {
         if (mLidState == LID_CLOSED && mLidControlsSleep) {
-            mPowerManager.goToSleep(SystemClock.uptimeMillis(),
-                    PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
+            goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
                     PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
         } else if (mLidState == LID_CLOSED && mLidControlsScreenLock) {
             mWindowManagerFuncs.lockDeviceNow();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 43ba094..2e4de8c 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -193,6 +193,11 @@
 
     Task mLastParent;
 
+    /**
+     * See {@link #canTurnScreenOn()}
+     */
+    private boolean mCanTurnScreenOn = true;
+
     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
@@ -290,7 +295,7 @@
         boolean nowGone = mReportedVisibilityResults.nowGone;
 
         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
-        boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
+        boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && !hidden;
         if (!nowGone) {
             // If the app is not yet gone, then it can only become visible/drawn.
             if (!nowDrawn) {
@@ -644,6 +649,8 @@
         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped
                 + " " + this);
         mAppStopped = false;
+        // Allow the window to turn the screen on once the app is resumed again.
+        setCanTurnScreenOn(true);
         if (!wasStopped) {
             destroySurfaces(true /*cleanupOnResume*/);
         }
@@ -1641,6 +1648,24 @@
     }
 
     /**
+     * Sets whether the current launch can turn the screen on. See {@link #canTurnScreenOn()}
+     */
+    void setCanTurnScreenOn(boolean canTurnScreenOn) {
+        mCanTurnScreenOn = canTurnScreenOn;
+    }
+
+    /**
+     * Indicates whether the current launch can turn the screen on. This is to prevent multiple
+     * relayouts from turning the screen back on. The screen should only turn on at most
+     * once per activity resume.
+     *
+     * @return true if the screen can be turned on.
+     */
+    boolean canTurnScreenOn() {
+        return mCanTurnScreenOn;
+    }
+
+    /**
      * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
      * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
      * we can't take a snapshot for other reasons, for example, if we have a secure window.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c610ca3..0cc505e 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1632,9 +1632,14 @@
                 // hidden while the screen is turning off.
                 // TODO(b/63773439): These cases should be eliminated, though we probably still
                 // want to process mTurnOnScreen in this way for clarity.
-                if (mWin.mTurnOnScreen) {
+                if (mWin.mTurnOnScreen && mWin.mAppToken.canTurnScreenOn()) {
                     if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
                     mWin.mTurnOnScreen = false;
+
+                    // The window should only turn the screen on once per resume, but
+                    // prepareSurfaceLocked can be called multiple times. Set canTurnScreenOn to
+                    // false so the window doesn't turn the screen on again during this resume.
+                    mWin.mAppToken.setCanTurnScreenOn(false);
                     mAnimator.mBulkUpdateParams |= SET_TURN_ON_SCREEN;
                 }
             }