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
This commit is contained in:
@@ -25,6 +25,7 @@ import android.os.PowerManager
|
||||
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.NotificationWakeUpCoordinator
|
||||
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 @@ import kotlin.math.max
|
||||
@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 @@ constructor(context: Context,
|
||||
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 @@ constructor(context: Context,
|
||||
}
|
||||
|
||||
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 @@ constructor(context: Context,
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
mDraggedFarEnough = false
|
||||
isExpanding = false
|
||||
leavingLockscreen = false
|
||||
mStartingChild = null
|
||||
mInitialTouchY = y
|
||||
mInitialTouchX = x
|
||||
@@ -114,29 +131,52 @@ constructor(context: Context,
|
||||
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()
|
||||
recycleVelocityTracker()
|
||||
}
|
||||
MotionEvent.ACTION_CANCEL -> cancelExpansion()
|
||||
}
|
||||
return isExpanding
|
||||
}
|
||||
@@ -147,12 +187,15 @@ constructor(context: Context,
|
||||
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 @@ constructor(context: Context,
|
||||
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 @@ constructor(context: Context,
|
||||
|
||||
private fun setEmptyDragAmount(amount: Float) {
|
||||
mEmptyDragAmount = amount
|
||||
mExpansionCallback!!.setEmptyDragAmount(amount)
|
||||
expansionCallback.setEmptyDragAmount(amount)
|
||||
}
|
||||
|
||||
private fun reset(child: ExpandableView) {
|
||||
@@ -234,7 +277,7 @@ constructor(context: Context,
|
||||
} else {
|
||||
resetClock()
|
||||
}
|
||||
mWakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */,
|
||||
wakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */,
|
||||
true /* animate */,
|
||||
false /* increaseSpeed */)
|
||||
isExpanding = false
|
||||
@@ -243,21 +286,21 @@ constructor(context: Context,
|
||||
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) {
|
||||
|
||||
@@ -89,6 +89,21 @@ class NotificationWakeUpCoordinator @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ class NotificationWakeUpCoordinator @Inject constructor(
|
||||
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
|
||||
|
||||
@@ -242,7 +242,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
|
||||
}
|
||||
}
|
||||
|
||||
private void startWakeAndUnlock(BiometricSourceType biometricSourceType) {
|
||||
public void startWakeAndUnlock(BiometricSourceType biometricSourceType) {
|
||||
startWakeAndUnlock(calculateMode(biometricSourceType));
|
||||
}
|
||||
|
||||
|
||||
@@ -33,20 +33,32 @@ class KeyguardBypassController {
|
||||
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 @@ class KeyguardBypassController {
|
||||
* @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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,6 +213,8 @@ public class NotificationPanelView extends PanelView implements
|
||||
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 @@ public class NotificationPanelView extends PanelView implements
|
||||
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 @@ public class NotificationPanelView extends PanelView implements
|
||||
mOnlyAffordanceInThisMotion = false;
|
||||
mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
|
||||
mDozingOnDown = isDozing();
|
||||
mDownX = event.getX();
|
||||
mDownY = event.getY();
|
||||
mCollapsedOnDown = isFullyCollapsed();
|
||||
mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
|
||||
}
|
||||
@@ -1076,7 +1081,8 @@ public class NotificationPanelView extends PanelView implements
|
||||
|| 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;
|
||||
}
|
||||
|
||||
@@ -786,6 +786,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
|
||||
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 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
notifyHeadsUpGoingToSleep();
|
||||
dismissVolumeDialog();
|
||||
mWakeUpCoordinator.setFullyAwake(false);
|
||||
mKeyguardBypassController.onStartedGoingToSleep();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -149,6 +149,7 @@ public class StatusBarWindowView extends FrameLayout {
|
||||
* 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 @@ public class StatusBarWindowView extends FrameLayout {
|
||||
if (mNotificationPanel.isFullyExpanded()
|
||||
&& mStatusBarStateController.getState() == StatusBarState.KEYGUARD
|
||||
&& !mService.isBouncerShowing()
|
||||
&& !mBypassController.getBypassEnabled()
|
||||
&& !mService.isDozing()) {
|
||||
intercept = mDragDownHelper.onInterceptTouchEvent(ev);
|
||||
}
|
||||
@@ -439,7 +441,8 @@ public class StatusBarWindowView extends FrameLayout {
|
||||
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 class StatusBarWindowView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void setBypassController(KeyguardBypassController bypassController) {
|
||||
mBypassController = bypassController;
|
||||
}
|
||||
|
||||
public class LayoutParams extends FrameLayout.LayoutParams {
|
||||
|
||||
public boolean ignoreRightInset;
|
||||
|
||||
@@ -118,7 +118,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user