Merge changes from topic "caitlinshk-cs-wakeupfromtouch" into udc-qpr-dev

* changes:
  [Central Surfaces] Replace mWakeUpComingFromTouch with KeyguardRepo.
  [Central Surfaces] Make KeyguardRepository.wakefulness a StateFlow.
This commit is contained in:
Caitlin Shkuratov
2023-05-31 21:00:55 +00:00
committed by Android (Google) Code Review
14 changed files with 142 additions and 63 deletions

View File

@@ -25,6 +25,7 @@ import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLoggin
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.Position
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.doze.DozeMachine
import com.android.systemui.doze.DozeTransitionCallback
@@ -44,13 +45,16 @@ import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
/** Defines interface for classes that encapsulate application state for the keyguard. */
interface KeyguardRepository {
@@ -138,7 +142,7 @@ interface KeyguardRepository {
val statusBarState: Flow<StatusBarState>
/** Observable for device wake/sleep state */
val wakefulness: Flow<WakefulnessModel>
val wakefulness: StateFlow<WakefulnessModel>
/** Observable for biometric unlock modes */
val biometricUnlockState: Flow<BiometricUnlockModel>
@@ -202,7 +206,8 @@ constructor(
private val dozeParameters: DozeParameters,
private val authController: AuthController,
private val dreamOverlayCallbackController: DreamOverlayCallbackController,
@Main private val mainDispatcher: CoroutineDispatcher
@Main private val mainDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
) : KeyguardRepository {
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
@@ -486,47 +491,48 @@ constructor(
awaitClose { biometricUnlockController.removeListener(callback) }
}
override val wakefulness: Flow<WakefulnessModel> = conflatedCallbackFlow {
val observer =
object : WakefulnessLifecycle.Observer {
override fun onStartedWakingUp() {
dispatchNewState()
}
override val wakefulness: StateFlow<WakefulnessModel> =
conflatedCallbackFlow {
val observer =
object : WakefulnessLifecycle.Observer {
override fun onStartedWakingUp() {
dispatchNewState()
}
override fun onFinishedWakingUp() {
dispatchNewState()
}
override fun onFinishedWakingUp() {
dispatchNewState()
}
override fun onPostFinishedWakingUp() {
dispatchNewState()
}
override fun onPostFinishedWakingUp() {
dispatchNewState()
}
override fun onStartedGoingToSleep() {
dispatchNewState()
}
override fun onStartedGoingToSleep() {
dispatchNewState()
}
override fun onFinishedGoingToSleep() {
dispatchNewState()
}
override fun onFinishedGoingToSleep() {
dispatchNewState()
}
private fun dispatchNewState() {
trySendWithFailureLogging(
WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle),
TAG,
"updated wakefulness state"
)
}
private fun dispatchNewState() {
trySendWithFailureLogging(
WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle),
TAG,
"updated wakefulness state",
)
}
}
wakefulnessLifecycle.addObserver(observer)
awaitClose { wakefulnessLifecycle.removeObserver(observer) }
}
wakefulnessLifecycle.addObserver(observer)
trySendWithFailureLogging(
WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle),
TAG,
"initial wakefulness state"
)
awaitClose { wakefulnessLifecycle.removeObserver(observer) }
}
.stateIn(
scope,
// Use Eagerly so that we're always listening and never miss an event.
SharingStarted.Eagerly,
initialValue = WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle),
)
override val fingerprintSensorLocation: Flow<Point?> = conflatedCallbackFlow {
fun sendFpLocation() {

View File

@@ -40,6 +40,7 @@ import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
@@ -99,7 +100,7 @@ constructor(
}
/** The device wake/sleep state */
val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
val wakefulnessModel: StateFlow<WakefulnessModel> = repository.wakefulness
/**
* Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means

View File

@@ -23,9 +23,12 @@ enum class WakeSleepReason {
/** The physical power button was pressed to wake up or sleep the device. */
POWER_BUTTON,
/** The user has taped or double tapped to wake the screen */
/** The user has tapped or double tapped to wake the screen. */
TAP,
/** The user performed some sort of gesture to wake the screen. */
GESTURE,
/** Something else happened to wake up or sleep the device. */
OTHER;
@@ -34,6 +37,7 @@ enum class WakeSleepReason {
return when (reason) {
PowerManager.WAKE_REASON_POWER_BUTTON -> POWER_BUTTON
PowerManager.WAKE_REASON_TAP -> TAP
PowerManager.WAKE_REASON_GESTURE -> GESTURE
else -> OTHER
}
}

View File

@@ -27,7 +27,11 @@ data class WakefulnessModel(
fun isStartingToSleep() = state == WakefulnessState.STARTING_TO_SLEEP
fun isStartingToSleepOrAsleep() = isStartingToSleep() || state == WakefulnessState.ASLEEP
private fun isAsleep() = state == WakefulnessState.ASLEEP
fun isStartingToSleepOrAsleep() = isStartingToSleep() || isAsleep()
fun isDeviceInteractive() = !isAsleep()
fun isStartingToSleepFromPowerButton() =
isStartingToSleep() && lastWakeReason == WakeSleepReason.POWER_BUTTON
@@ -41,6 +45,11 @@ data class WakefulnessModel(
fun isAwakeFromTap() =
state == WakefulnessState.STARTING_TO_WAKE && lastWakeReason == WakeSleepReason.TAP
fun isDeviceInteractiveFromTapOrGesture(): Boolean {
return isDeviceInteractive() &&
(lastWakeReason == WakeSleepReason.TAP || lastWakeReason == WakeSleepReason.GESTURE)
}
companion object {
fun fromWakefulnessLifecycle(wakefulnessLifecycle: WakefulnessLifecycle): WakefulnessModel {
return WakefulnessModel(

View File

@@ -134,6 +134,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.shared.model.WakefulnessModel;
import com.android.systemui.keyguard.ui.binder.KeyguardLongPressViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
@@ -2150,10 +2151,14 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
int getFalsingThreshold() {
float factor = mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
float factor = ShadeViewController.getFalsingThresholdFactor(getWakefulness());
return (int) (mQsController.getFalsingThreshold() * factor);
}
private WakefulnessModel getWakefulness() {
return mKeyguardInteractor.getWakefulnessModel().getValue();
}
private void maybeAnimateBottomAreaAlpha() {
mBottomAreaShadeAlphaAnimator.cancel();
if (mBarState == StatusBarState.SHADE_LOCKED) {
@@ -3587,8 +3592,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
expand = flingExpands(vel, vectorVel, x, y);
}
mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
mCentralSurfaces.isWakeUpComingFromTouch());
mDozeLog.traceFling(
expand,
mTouchAboveFalsingThreshold,
/* screenOnFromTouch=*/ getWakefulness().isDeviceInteractiveFromTapOrGesture());
// Log collapse gesture if on lock screen.
if (!expand && onKeyguard) {
float displayDensity = mCentralSurfaces.getDisplayDensity();

View File

@@ -17,6 +17,7 @@ package com.android.systemui.shade
import android.view.MotionEvent
import android.view.ViewGroup
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.statusbar.RemoteInputController
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
@@ -218,6 +219,16 @@ interface ShadeViewController {
val shadeNotificationPresenter: ShadeNotificationPresenter
companion object {
/**
* Returns a multiplicative factor to use when determining the falsing threshold for touches
* on the shade. The factor will be larger when the device is waking up due to a touch or
* gesture.
*/
@JvmStatic
fun getFalsingThresholdFactor(wakefulness: WakefulnessModel): Float {
return if (wakefulness.isDeviceInteractiveFromTapOrGesture()) 1.5f else 1.0f
}
const val WAKEUP_ANIMATION_DELAY_MS = 250
const val FLING_MAX_LENGTH_SECONDS = 0.6f
const val FLING_SPEED_UP_FACTOR = 0.6f

View File

@@ -61,6 +61,7 @@ import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -69,6 +70,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEv
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
@@ -170,6 +172,7 @@ public class NotificationStackScrollLayoutController {
private final KeyguardMediaController mKeyguardMediaController;
private final SysuiStatusBarStateController mStatusBarStateController;
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardInteractor mKeyguardInteractor;
private final NotificationLockscreenUserManager mLockscreenUserManager;
// TODO: CentralSurfaces should be encapsulated behind a Controller
private final CentralSurfaces mCentralSurfaces;
@@ -558,7 +561,8 @@ public class NotificationStackScrollLayoutController {
@Override
public float getFalsingThresholdFactor() {
return mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
return ShadeViewController.getFalsingThresholdFactor(
mKeyguardInteractor.getWakefulnessModel().getValue());
}
@Override
@@ -622,6 +626,7 @@ public class NotificationStackScrollLayoutController {
SysuiStatusBarStateController statusBarStateController,
KeyguardMediaController keyguardMediaController,
KeyguardBypassController keyguardBypassController,
KeyguardInteractor keyguardInteractor,
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
Optional<NotificationListViewModel> nsslViewModel,
@@ -669,6 +674,7 @@ public class NotificationStackScrollLayoutController {
mStatusBarStateController = statusBarStateController;
mKeyguardMediaController = keyguardMediaController;
mKeyguardBypassController = keyguardBypassController;
mKeyguardInteractor = keyguardInteractor;
mZenModeController = zenModeController;
mLockscreenUserManager = lockscreenUserManager;
mViewModel = nsslViewModel;

View File

@@ -224,8 +224,6 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner {
boolean isLaunchingActivityOverLockscreen();
boolean isWakeUpComingFromTouch();
void onKeyguardViewManagerStatesUpdated();
boolean isPulsing();

View File

@@ -466,8 +466,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private final LightRevealScrim mLightRevealScrim;
private PowerButtonReveal mPowerButtonReveal;
private boolean mWakeUpComingFromTouch;
/**
* Whether we should delay the wakeup animation (which shows the notifications and moves the
* clock view). This is typically done when waking up from a 'press to unlock' gesture on a
@@ -1625,7 +1623,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
if (mDozing && mScreenOffAnimationController.allowWakeUpIfDozing()) {
mPowerManager.wakeUp(
time, wakeReason, "com.android.systemui:" + why);
mWakeUpComingFromTouch = true;
mFalsingCollector.onScreenOnFromTouch();
}
}
@@ -1802,11 +1799,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
return mIsLaunchingActivityOverLockscreen;
}
@Override
public boolean isWakeUpComingFromTouch() {
return mWakeUpComingFromTouch;
}
/**
* To be called when there's a state change in StatusBarKeyguardViewManager.
*/
@@ -1935,7 +1927,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_APPLICATION,
"com.android.systemui:full_screen_intent");
mWakeUpComingFromTouch = false;
}
}
@@ -3116,7 +3107,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
releaseGestureWakeLock();
mLaunchCameraWhenFinishedWaking = false;
mDeviceInteractive = false;
mWakeUpComingFromTouch = false;
updateVisibleToUser();
updateNotificationPanelTouchState();

View File

@@ -97,7 +97,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
dozeParameters,
authController,
dreamOverlayCallbackController,
mainDispatcher
mainDispatcher,
testScope.backgroundScope,
)
}
@@ -343,8 +344,6 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
)
job.cancel()
runCurrent()
verify(wakefulnessLifecycle).removeObserver(captor.value)
}
@Test

View File

@@ -315,6 +315,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
protected final int mMaxUdfpsBurnInOffsetY = 5;
protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
protected FakeKeyguardRepository mFakeKeyguardRepository;
protected KeyguardInteractor mKeyguardInteractor;
protected NotificationPanelViewController.TouchHandler mTouchHandler;
protected ConfigurationController mConfigurationController;
@@ -342,10 +343,12 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
mMainDispatcher = getMainDispatcher();
mKeyguardBottomAreaInteractor = new KeyguardBottomAreaInteractor(
new FakeKeyguardRepository());
KeyguardInteractorFactory.WithDependencies keyguardInteractorDeps =
KeyguardInteractorFactory.create();
mFakeKeyguardRepository = keyguardInteractorDeps.getRepository();
mKeyguardBottomAreaInteractor = new KeyguardBottomAreaInteractor(mFakeKeyguardRepository);
mKeyguardInteractor = keyguardInteractorDeps.getKeyguardInteractor();
mKeyguardInteractor = KeyguardInteractorFactory.create().getKeyguardInteractor();
SystemClock systemClock = new FakeSystemClock();
mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
mInteractionJankMonitor, mShadeExpansionStateManager);

View File

@@ -58,6 +58,9 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.systemui.DejankUtils;
import com.android.systemui.R;
import com.android.systemui.keyguard.shared.model.WakeSleepReason;
import com.android.systemui.keyguard.shared.model.WakefulnessModel;
import com.android.systemui.keyguard.shared.model.WakefulnessState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
@@ -1162,4 +1165,43 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo
when(mUnlockedScreenOffAnimationController.isAnimationPlaying()).thenReturn(true);
assertThat(mNotificationPanelViewController.isExpanded()).isTrue();
}
@Test
public void getFalsingThreshold_deviceNotInteractive_isQsThreshold() {
mFakeKeyguardRepository.setWakefulnessModel(
new WakefulnessModel(
WakefulnessState.ASLEEP,
/* lastWakeReason= */ WakeSleepReason.TAP,
/* lastSleepReason= */ WakeSleepReason.POWER_BUTTON)
);
when(mQsController.getFalsingThreshold()).thenReturn(14);
assertThat(mNotificationPanelViewController.getFalsingThreshold()).isEqualTo(14);
}
@Test
public void getFalsingThreshold_lastWakeNotDueToTouch_isQsThreshold() {
mFakeKeyguardRepository.setWakefulnessModel(
new WakefulnessModel(
WakefulnessState.AWAKE,
/* lastWakeReason= */ WakeSleepReason.POWER_BUTTON,
/* lastSleepReason= */ WakeSleepReason.POWER_BUTTON)
);
when(mQsController.getFalsingThreshold()).thenReturn(14);
assertThat(mNotificationPanelViewController.getFalsingThreshold()).isEqualTo(14);
}
@Test
public void getFalsingThreshold_lastWakeDueToTouch_greaterThanQsThreshold() {
mFakeKeyguardRepository.setWakefulnessModel(
new WakefulnessModel(
WakefulnessState.AWAKE,
/* lastWakeReason= */ WakeSleepReason.TAP,
/* lastSleepReason= */ WakeSleepReason.POWER_BUTTON)
);
when(mQsController.getFalsingThreshold()).thenReturn(14);
assertThat(mNotificationPanelViewController.getFalsingThreshold()).isGreaterThan(14);
}
}

View File

@@ -47,6 +47,7 @@ import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -117,6 +118,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
@Mock private KeyguardMediaController mKeyguardMediaController;
@Mock private SysuiStatusBarStateController mSysuiStatusBarStateController;
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private KeyguardInteractor mKeyguardInteractor;
@Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock private MetricsLogger mMetricsLogger;
@Mock private DumpManager mDumpManager;
@@ -463,6 +465,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mSysuiStatusBarStateController,
mKeyguardMediaController,
mKeyguardBypassController,
mKeyguardInteractor,
mZenModeController,
mNotificationLockscreenUserManager,
Optional.<NotificationListViewModel>empty(),

View File

@@ -81,7 +81,7 @@ class FakeKeyguardRepository : KeyguardRepository {
MutableStateFlow(
WakefulnessModel(WakefulnessState.ASLEEP, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
)
override val wakefulness: Flow<WakefulnessModel> = _wakefulnessModel
override val wakefulness = _wakefulnessModel
private val _isUdfpsSupported = MutableStateFlow(false)