Enabled dragging down from the lock screen when bypassing
The pulseExpansionHandler now also works on the lockscreen.
This also delays the bypass when the user is currently
dragging down.
Bug: 134094877
Bug: 130327302
Test: atest SystemUITests
Change-Id: I8d5b5b53e9a68e08933866df6831ecbada41ce43
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index a9d4fde..e132209c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -25,6 +25,7 @@
import android.os.PowerManager.WAKE_REASON_GESTURE
import android.os.SystemClock
import android.view.MotionEvent
+import android.view.VelocityTracker
import android.view.ViewConfiguration
import com.android.systemui.Gefingerpoken
@@ -36,6 +37,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.ShadeController
import javax.inject.Inject
@@ -48,22 +50,31 @@
@Singleton
class PulseExpansionHandler @Inject
constructor(context: Context,
- private val mWakeUpCoordinator: NotificationWakeUpCoordinator) : Gefingerpoken {
+ private val wakeUpCoordinator: NotificationWakeUpCoordinator,
+ private val bypassController: KeyguardBypassController) : Gefingerpoken {
companion object {
private val RUBBERBAND_FACTOR_STATIC = 0.25f
private val SPRING_BACK_ANIMATION_LENGTH_MS = 375
}
private val mPowerManager: PowerManager?
- private var mShadeController: ShadeController? = null
+ private lateinit var shadeController: ShadeController
private val mMinDragDistance: Int
private var mInitialTouchX: Float = 0.0f
private var mInitialTouchY: Float = 0.0f
- var isExpanding: Boolean = false
- private set
+ private var isExpanding: Boolean = false
+ private set(value) {
+ val changed = field != value
+ field = value
+ bypassController.isPulseExpanding = value
+ if (changed && !value && !leavingLockscreen) {
+ bypassController.maybePerformPendingUnlock()
+ }
+ }
+ private var leavingLockscreen: Boolean = false
private val mTouchSlop: Float
- private var mExpansionCallback: ExpansionCallback? = null
- private lateinit var mStackScroller: NotificationStackScrollLayout
+ private lateinit var expansionCallback: ExpansionCallback
+ private lateinit var stackScroller: NotificationStackScrollLayout
private val mTemp2 = IntArray(2)
private var mDraggedFarEnough: Boolean = false
private var mStartingChild: ExpandableView? = null
@@ -74,6 +85,7 @@
private var mEmptyDragAmount: Float = 0.0f
private var mWakeUpHeight: Float = 0.0f
private var mReachedWakeUpHeight: Boolean = false
+ private var velocityTracker: VelocityTracker? = null
private val isFalseTouch: Boolean
get() = mFalsingManager.isFalseTouch
@@ -91,9 +103,13 @@
}
private fun maybeStartExpansion(event: MotionEvent): Boolean {
- if (!mPulsing) {
+ if (!wakeUpCoordinator.canShowPulsingHuns) {
return false
}
+ if (velocityTracker == null) {
+ velocityTracker = VelocityTracker.obtain()
+ }
+ velocityTracker!!.addMovement(event)
val x = event.x
val y = event.y
@@ -101,6 +117,7 @@
MotionEvent.ACTION_DOWN -> {
mDraggedFarEnough = false
isExpanding = false
+ leavingLockscreen = false
mStartingChild = null
mInitialTouchY = y
mInitialTouchX = x
@@ -114,29 +131,52 @@
captureStartingChild(mInitialTouchX, mInitialTouchY)
mInitialTouchY = y
mInitialTouchX = x
- mWakeUpHeight = mWakeUpCoordinator.getWakeUpHeight()
+ mWakeUpHeight = wakeUpCoordinator.getWakeUpHeight()
mReachedWakeUpHeight = false
return true
}
}
+
+ MotionEvent.ACTION_UP -> {
+ recycleVelocityTracker();
+ }
+
+ MotionEvent.ACTION_CANCEL -> {
+ recycleVelocityTracker();
+ }
}
return false
}
+ private fun recycleVelocityTracker() {
+ velocityTracker?.recycle();
+ velocityTracker = null
+ }
+
override fun onTouchEvent(event: MotionEvent): Boolean {
if (!isExpanding) {
return maybeStartExpansion(event)
}
+ velocityTracker!!.addMovement(event)
val y = event.y
+ val moveDistance = y - mInitialTouchY
when (event.actionMasked) {
- MotionEvent.ACTION_MOVE -> updateExpansionHeight(y - mInitialTouchY)
- MotionEvent.ACTION_UP -> if (!mFalsingManager.isUnlockingDisabled && !isFalseTouch) {
- finishExpansion()
- } else {
- cancelExpansion()
+ MotionEvent.ACTION_MOVE -> updateExpansionHeight(moveDistance)
+ MotionEvent.ACTION_UP -> {
+ velocityTracker!!.computeCurrentVelocity(1000 /* units */)
+ val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000
+ if (!mFalsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) {
+ finishExpansion()
+ } else {
+ cancelExpansion()
+ }
+ recycleVelocityTracker()
}
- MotionEvent.ACTION_CANCEL -> cancelExpansion()
+ MotionEvent.ACTION_CANCEL -> {
+ cancelExpansion()
+ recycleVelocityTracker()
+ }
}
return isExpanding
}
@@ -147,12 +187,15 @@
setUserLocked(mStartingChild!!, false)
mStartingChild = null
}
+ if (shadeController.isDozing) {
+ isWakingToShadeLocked = true
+ wakeUpCoordinator.willWakeUp = true
+ mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE,
+ "com.android.systemui:PULSEDRAG")
+ }
+ shadeController.goToLockedShade(mStartingChild)
+ leavingLockscreen = true;
isExpanding = false
- isWakingToShadeLocked = true
- mWakeUpCoordinator.willWakeUp = true
- mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE,
- "com.android.systemui:PULSEDRAG")
- mShadeController!!.goToLockedShade(mStartingChild)
if (mStartingChild is ExpandableNotificationRow) {
val row = mStartingChild as ExpandableNotificationRow?
row!!.onExpandedByGesture(true /* userExpanded */)
@@ -172,12 +215,12 @@
expansionHeight = max(newHeight.toFloat(), expansionHeight)
} else {
val target = if (mReachedWakeUpHeight) mWakeUpHeight else 0.0f
- mWakeUpCoordinator.setNotificationsVisibleForExpansion(height > target,
+ wakeUpCoordinator.setNotificationsVisibleForExpansion(height > target,
true /* animate */,
true /* increaseSpeed */)
expansionHeight = max(mWakeUpHeight, expansionHeight)
}
- val emptyDragAmount = mWakeUpCoordinator.setPulseHeight(expansionHeight)
+ val emptyDragAmount = wakeUpCoordinator.setPulseHeight(expansionHeight)
setEmptyDragAmount(emptyDragAmount * RUBBERBAND_FACTOR_STATIC)
}
@@ -192,7 +235,7 @@
private fun setEmptyDragAmount(amount: Float) {
mEmptyDragAmount = amount
- mExpansionCallback!!.setEmptyDragAmount(amount)
+ expansionCallback.setEmptyDragAmount(amount)
}
private fun reset(child: ExpandableView) {
@@ -234,7 +277,7 @@
} else {
resetClock()
}
- mWakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */,
+ wakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */,
true /* animate */,
false /* increaseSpeed */)
isExpanding = false
@@ -243,21 +286,21 @@
private fun findView(x: Float, y: Float): ExpandableView? {
var totalX = x
var totalY = y
- mStackScroller.getLocationOnScreen(mTemp2)
+ stackScroller.getLocationOnScreen(mTemp2)
totalX += mTemp2[0].toFloat()
totalY += mTemp2[1].toFloat()
- val childAtRawPosition = mStackScroller.getChildAtRawPosition(totalX, totalY)
+ val childAtRawPosition = stackScroller.getChildAtRawPosition(totalX, totalY)
return if (childAtRawPosition != null && childAtRawPosition.isContentExpandable) {
childAtRawPosition
} else null
}
- fun setUp(notificationStackScroller: NotificationStackScrollLayout,
- expansionCallback: ExpansionCallback,
- shadeController: ShadeController) {
- mExpansionCallback = expansionCallback
- mShadeController = shadeController
- mStackScroller = notificationStackScroller
+ fun setUp(stackScroller: NotificationStackScrollLayout,
+ expansionCallback: ExpansionCallback,
+ shadeController: ShadeController) {
+ this.expansionCallback = expansionCallback
+ this.shadeController = shadeController
+ this.stackScroller = stackScroller
}
fun setPulsing(pulsing: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index bf25c45..1f3675a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -89,6 +89,21 @@
}
}
+ /**
+ * True if we can show pulsing heads up notifications
+ */
+ var canShowPulsingHuns: Boolean = false
+ private set
+ get() {
+ var canShow = pulsing
+ if (bypassController.bypassEnabled) {
+ // We also allow pulsing on the lock screen!
+ canShow = canShow || (mWakingUp || willWakeUp || fullyAwake)
+ && mStatusBarStateController.state == StatusBarState.KEYGUARD
+ }
+ return canShow
+ }
+
init {
mHeadsUpManagerPhone.addListener(this)
@@ -120,13 +135,7 @@
private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) {
// TODO: handle Lockscreen wakeup for bypass when we're not pulsing anymore
var visible = mNotificationsVisibleForExpansion || mHeadsUpManagerPhone.hasNotifications()
- var canShow = pulsing
- if (bypassController.bypassEnabled) {
- // We also allow pulsing on the lock screen!
- canShow = canShow || (mWakingUp || willWakeUp || fullyAwake)
- && mStatusBarStateController.state == StatusBarState.KEYGUARD
- }
- visible = visible && canShow
+ visible = visible && canShowPulsingHuns
if (!visible && mNotificationsVisible && (mWakingUp || willWakeUp) && mDozeAmount != 0.0f) {
// let's not make notifications invisible while waking up, otherwise the animation
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 35df7d92..3f6144e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -242,7 +242,7 @@
}
}
- private void startWakeAndUnlock(BiometricSourceType biometricSourceType) {
+ public void startWakeAndUnlock(BiometricSourceType biometricSourceType) {
startWakeAndUnlock(calculateMode(biometricSourceType));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 9bbe4be..56b64df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -33,20 +33,32 @@
private val unlockMethodCache: UnlockMethodCache
private val statusBarStateController: StatusBarStateController
- /**
- * If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
- */
+ lateinit var unlockController: BiometricUnlockController
+ var isPulseExpanding = false
+
+ /**
+ * If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
+ */
var bypassEnabled: Boolean = false
get() = field && unlockMethodCache.isUnlockingWithFacePossible
private set
-
- lateinit var unlockController: BiometricUnlockController
+ /**
+ * The pending unlock type which is set if the bypass was blocked when it happened.
+ */
+ private var pendingUnlockType: BiometricSourceType? = null
@Inject
constructor(context: Context, tunerService: TunerService,
statusBarStateController: StatusBarStateController) {
unlockMethodCache = UnlockMethodCache.getInstance(context)
this.statusBarStateController = statusBarStateController
+ statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+ override fun onStateChanged(newState: Int) {
+ if (newState != StatusBarState.KEYGUARD) {
+ pendingUnlockType = null;
+ }
+ }
+ })
val faceManager = context.getSystemService(FaceManager::class.java)
if (faceManager?.isHardwareDetected != true) {
return
@@ -72,11 +84,30 @@
* @return false if we can not wake and unlock right now
*/
fun onBiometricAuthenticated(biometricSourceType: BiometricSourceType): Boolean {
- if (bypassEnabled && statusBarStateController.state != StatusBarState.KEYGUARD) {
- // We're bypassing but not actually on the lockscreen, the user should decide when
- // to unlock
- return false
+ if (bypassEnabled) {
+ if (statusBarStateController.state != StatusBarState.KEYGUARD) {
+ // We're bypassing but not actually on the lockscreen, the user should decide when
+ // to unlock
+ return false
+ }
+ if (isPulseExpanding) {
+ pendingUnlockType = biometricSourceType
+ return false
+ }
}
return true
}
+
+ fun maybePerformPendingUnlock() {
+ if (pendingUnlockType != null) {
+ if (onBiometricAuthenticated(pendingUnlockType!!)) {
+ unlockController.startWakeAndUnlock(pendingUnlockType)
+ pendingUnlockType = null
+ }
+ }
+ }
+
+ fun onStartedGoingToSleep() {
+ pendingUnlockType = null
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 56a6154..626e62e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -213,6 +213,8 @@
private int mNotificationsHeaderCollideDistance;
private int mUnlockMoveDistance;
private float mEmptyDragAmount;
+ private float mDownX;
+ private float mDownY;
private final KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
new KeyguardClockPositionAlgorithm();
@@ -902,7 +904,8 @@
MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
return true;
}
- if (mPulseExpansionHandler.onInterceptTouchEvent(event)) {
+ if (!shouldQuickSettingsIntercept(mDownX, mDownY, 0)
+ && mPulseExpansionHandler.onInterceptTouchEvent(event)) {
return true;
}
@@ -1003,6 +1006,8 @@
mOnlyAffordanceInThisMotion = false;
mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
mDozingOnDown = isDozing();
+ mDownX = event.getX();
+ mDownY = event.getY();
mCollapsedOnDown = isFullyCollapsed();
mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
}
@@ -1076,7 +1081,8 @@
|| event.getAction() == MotionEvent.ACTION_CANCEL) {
mBlockingExpansionForCurrentTouch = false;
}
- if (!mIsExpanding && mPulseExpansionHandler.onTouchEvent(event)) {
+ if (!mIsExpanding && !shouldQuickSettingsIntercept(mDownX, mDownY, 0)
+ && mPulseExpansionHandler.onTouchEvent(event)) {
// We're expanding all the other ones shouldn't get this anymore
return true;
}
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 43e7a7b..0902484 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -786,6 +786,7 @@
inflateStatusBarWindow(context);
mStatusBarWindow.setService(this);
+ mStatusBarWindow.setBypassController(mKeyguardBypassController);
mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
// TODO: Deal with the ugliness that comes from having some of the statusbar broken out
@@ -3622,6 +3623,7 @@
notifyHeadsUpGoingToSleep();
dismissVolumeDialog();
mWakeUpCoordinator.setFullyAwake(false);
+ mKeyguardBypassController.onStartedGoingToSleep();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index de26659..9417295 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -149,6 +149,7 @@
* events manually as it's outside of the regular view bounds.
*/
private boolean mExpandingBelowNotch;
+ private KeyguardBypassController mBypassController;
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -417,6 +418,7 @@
if (mNotificationPanel.isFullyExpanded()
&& mStatusBarStateController.getState() == StatusBarState.KEYGUARD
&& !mService.isBouncerShowing()
+ && !mBypassController.getBypassEnabled()
&& !mService.isDozing()) {
intercept = mDragDownHelper.onInterceptTouchEvent(ev);
}
@@ -439,7 +441,8 @@
if (mService.isDozing()) {
handled = !mService.isPulsing();
}
- if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled)
+ if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled
+ && !mBypassController.getBypassEnabled())
|| mDragDownHelper.isDraggingDown()) {
// we still want to finish our drag down gesture when locking the screen
handled = mDragDownHelper.onTouchEvent(ev);
@@ -518,6 +521,10 @@
}
}
+ public void setBypassController(KeyguardBypassController bypassController) {
+ mBypassController = bypassController;
+ }
+
public class LayoutParams extends FrameLayout.LayoutParams {
public boolean ignoreRightInset;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 747411a..7742023 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -118,7 +118,8 @@
mock(HeadsUpManagerPhone.class),
new StatusBarStateControllerImpl(),
bypassController);
- PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator);
+ PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator,
+ bypassController);
mNotificationPanelView = new TestableNotificationPanelView(coordinator, expansionHandler,
bypassController);
mNotificationPanelView.setHeadsUpManager(mHeadsUpManager);