Allow camera launch also when device is interactive

Bug: 23967648
Change-Id: If91df75e6325b3969dc2351a70af0c160d3eab04
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 70c8a53..33c59f8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -154,6 +154,7 @@
     private static final int NOTIFY_STARTED_WAKING_UP = 21;
     private static final int NOTIFY_SCREEN_TURNED_ON = 22;
     private static final int NOTIFY_SCREEN_TURNED_OFF = 23;
+    private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 24;
 
     /**
      * The default amount of time we stay awake (used for all key input)
@@ -676,6 +677,7 @@
                 playSounds(true);
             }
         }
+        notifyStartedGoingToSleep();
     }
 
     public void onFinishedGoingToSleep(int why) {
@@ -1092,6 +1094,11 @@
         mHandler.sendEmptyMessage(VERIFY_UNLOCK);
     }
 
+    private void notifyStartedGoingToSleep() {
+        if (DEBUG) Log.d(TAG, "notifyStartedGoingToSleep");
+        mHandler.sendEmptyMessage(NOTIFY_STARTED_GOING_TO_SLEEP);
+    }
+
     private void notifyFinishedGoingToSleep() {
         if (DEBUG) Log.d(TAG, "notifyFinishedGoingToSleep");
         mHandler.sendEmptyMessage(NOTIFY_FINISHED_GOING_TO_SLEEP);
@@ -1203,6 +1210,9 @@
                 case VERIFY_UNLOCK:
                     handleVerifyUnlock();
                     break;
+                case NOTIFY_STARTED_GOING_TO_SLEEP:
+                    handleNotifyStartedGoingToSleep();
+                    break;
                 case NOTIFY_FINISHED_GOING_TO_SLEEP:
                     handleNotifyFinishedGoingToSleep();
                     break;
@@ -1530,6 +1540,13 @@
         }
     }
 
+    private void handleNotifyStartedGoingToSleep() {
+        synchronized (KeyguardViewMediator.this) {
+            if (DEBUG) Log.d(TAG, "handleNotifyStartedGoingToSleep");
+            mStatusBarKeyguardViewManager.onStartedGoingToSleep();
+        }
+    }
+
     /**
      * Handle message sent by {@link #notifyFinishedGoingToSleep()}
      * @see #NOTIFY_FINISHED_GOING_TO_SLEEP
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 59aa920..2bedef7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -488,12 +488,18 @@
     private boolean mLaunchTransitionFadingAway;
     private ExpandableNotificationRow mDraggedDownRow;
     private boolean mLaunchCameraOnScreenTurningOn;
+    private boolean mLaunchCameraOnFinishedGoingToSleep;
     private PowerManager.WakeLock mGestureWakeLock;
     private Vibrator mVibrator;
 
     // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
     private int mLastLoggedStateFingerprint;
 
+    /**
+     * If set, the device has started going to sleep but isn't fully non-interactive yet.
+     */
+    protected boolean mStartedGoingToSleep;
+
     private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD
             | StackViewState.LOCATION_MAIN_AREA;
 
@@ -3908,15 +3914,32 @@
         disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
     }
 
+    public void onStartedGoingToSleep() {
+        mStartedGoingToSleep = true;
+    }
+
     public void onFinishedGoingToSleep() {
         mNotificationPanel.onAffordanceLaunchEnded();
         releaseGestureWakeLock();
         mLaunchCameraOnScreenTurningOn = false;
+        mStartedGoingToSleep = false;
         mDeviceInteractive = false;
         mWakeUpComingFromTouch = false;
         mWakeUpTouchLocation = null;
         mStackScroller.setAnimationsEnabled(false);
         updateVisibleToUser();
+        if (mLaunchCameraOnFinishedGoingToSleep) {
+            mLaunchCameraOnFinishedGoingToSleep = false;
+
+            // This gets executed before we will show Keyguard, so post it in order that the state
+            // is correct.
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onCameraLaunchGestureDetected();
+                }
+            });
+        }
     }
 
     public void onStartedWakingUp() {
@@ -3936,7 +3959,8 @@
     }
 
     private void vibrateForCameraGesture() {
-        mVibrator.vibrate(750L);
+        // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
+        mVibrator.vibrate(new long[] { 0, 750L }, -1 /* repeat */);
     }
 
     public void onScreenTurnedOn() {
@@ -4095,6 +4119,10 @@
 
     @Override
     public void onCameraLaunchGestureDetected() {
+        if (mStartedGoingToSleep) {
+            mLaunchCameraOnFinishedGoingToSleep = true;
+            return;
+        }
         if (!mNotificationPanel.canCameraGestureBeLaunched(
                 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
             return;
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 e26f423..394ff3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -164,6 +164,10 @@
         }
     }
 
+    public void onStartedGoingToSleep() {
+        mPhoneStatusBar.onStartedGoingToSleep();
+    }
+
     public void onFinishedGoingToSleep() {
         mDeviceInteractive = false;
         mPhoneStatusBar.onFinishedGoingToSleep();
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 69f0cef..bd7d4b2 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -101,8 +101,8 @@
      * Whether camera double tap power button gesture is currently enabled;
      */
     private boolean mCameraDoubleTapPowerEnabled;
-    private long mLastPowerDownWhileNonInteractive = 0;
-
+    private long mLastPowerDownWhileNonInteractive;
+    private long mLastPowerDownWhileInteractive;
 
     public GestureLauncherService(Context context) {
         super(context);
@@ -251,23 +251,30 @@
 
     public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive) {
         boolean launched = false;
+        boolean intercept = false;
         synchronized (this) {
             if (!mCameraDoubleTapPowerEnabled) {
                 mLastPowerDownWhileNonInteractive = 0;
+                mLastPowerDownWhileInteractive = 0;
                 return false;
             }
             if (event.getEventTime() - mLastPowerDownWhileNonInteractive
                     < CAMERA_POWER_DOUBLE_TAP_TIME_MS) {
                 launched = true;
+                intercept = true;
+            } else if (event.getEventTime() - mLastPowerDownWhileInteractive
+                    < CAMERA_POWER_DOUBLE_TAP_TIME_MS) {
+                launched = true;
             }
             mLastPowerDownWhileNonInteractive = interactive ? 0 : event.getEventTime();
+            mLastPowerDownWhileInteractive = interactive ? event.getEventTime() : 0;
         }
         if (launched) {
             Slog.i(TAG, "Power button double tap gesture detected, launching camera.");
             launched = handleCameraLaunchGesture(false /* useWakelock */,
                     MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE);
         }
-        return launched;
+        return intercept && launched;
     }
 
     /**
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 30f4dce..c228422 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -59,6 +59,7 @@
         implements InputManager.InputDeviceListener {
     private static final String TAG = "VibratorService";
     private static final boolean DEBUG = false;
+    private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
 
     private final LinkedList<Vibration> mVibrations;
     private final LinkedList<VibrationInfo> mPreviousVibrations;
@@ -147,7 +148,8 @@
         }
 
         public boolean isSystemHapticFeedback() {
-            return (mUid == Process.SYSTEM_UID || mUid == 0) && mRepeat < 0;
+            return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
+                    && mRepeat < 0;
         }
     }