Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8cc6efc authored by Selim Cinek's avatar Selim Cinek
Browse files

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
parent b57dd8ab
Loading
Loading
Loading
Loading
+73 −30
Original line number Diff line number Diff line
@@ -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) {
            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()
                }
            MotionEvent.ACTION_CANCEL -> cancelExpansion()
                recycleVelocityTracker()
            }
            MotionEvent.ACTION_CANCEL -> {
                cancelExpansion()
                recycleVelocityTracker()
            }
        }
        return isExpanding
    }
@@ -147,12 +187,15 @@ constructor(context: Context,
            setUserLocked(mStartingChild!!, false)
            mStartingChild = null
        }
        isExpanding = false
        if (shadeController.isDozing) {
            isWakingToShadeLocked = true
        mWakeUpCoordinator.willWakeUp = true
            wakeUpCoordinator.willWakeUp = true
            mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE,
                    "com.android.systemui:PULSEDRAG")
        mShadeController!!.goToLockedShade(mStartingChild)
        }
        shadeController.goToLockedShade(mStartingChild)
        leavingLockscreen = true;
        isExpanding = false
        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,
    fun setUp(stackScroller: NotificationStackScrollLayout,
              expansionCallback: ExpansionCallback,
              shadeController: ShadeController) {
        mExpansionCallback = expansionCallback
        mShadeController = shadeController
        mStackScroller = notificationStackScroller
        this.expansionCallback = expansionCallback
        this.shadeController = shadeController
        this.stackScroller = stackScroller
    }

    fun setPulsing(pulsing: Boolean) {
+16 −7
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -242,7 +242,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
        }
    }

    private void startWakeAndUnlock(BiometricSourceType biometricSourceType) {
    public void startWakeAndUnlock(BiometricSourceType biometricSourceType) {
        startWakeAndUnlock(calculateMode(biometricSourceType));
    }

+40 −9
Original line number Diff line number Diff line
@@ -33,20 +33,32 @@ class KeyguardBypassController {
    private val unlockMethodCache: UnlockMethodCache
    private val statusBarStateController: StatusBarStateController

    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) {
        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
    }
}
+8 −2
Original line number Diff line number Diff line
@@ -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;
        }
Loading