Do not animate statusbar unfold when in portrait orientation
Disables unfold animation for statusbar when it is perpendicular to the screen fold. Moves ScopedUnfoldTransitionProgressProvider from launcher to shared SysUI/Launcher code. Introduces NaturalRotationUnfoldProgressProvider which emits transition events only when in natural rotation. Added proper disposal of resources when status bar is detached as PhoneStatusBarView is re-created when folding/unfolding. Bug: 201518277 Test: manual Test: atest com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProviderTest Change-Id: If4da3afca2b41c3675ccf6838e9ad6dac1b6f82e
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package com.android.systemui.unfold.util
|
||||
|
||||
import android.content.Context
|
||||
import android.os.RemoteException
|
||||
import android.util.Log
|
||||
import android.view.IRotationWatcher
|
||||
import android.view.IWindowManager
|
||||
import android.view.Surface
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
||||
|
||||
/**
|
||||
* [UnfoldTransitionProgressProvider] that emits transition progress only when the display has
|
||||
* default rotation or 180 degrees opposite rotation (ROTATION_0 or ROTATION_180).
|
||||
* It could be helpful to run the animation only when the display's rotation is perpendicular
|
||||
* to the fold.
|
||||
*/
|
||||
class NaturalRotationUnfoldProgressProvider(
|
||||
private val context: Context,
|
||||
private val windowManagerInterface: IWindowManager,
|
||||
unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider
|
||||
) : UnfoldTransitionProgressProvider {
|
||||
|
||||
private val scopedUnfoldTransitionProgressProvider =
|
||||
ScopedUnfoldTransitionProgressProvider(unfoldTransitionProgressProvider)
|
||||
private val rotationWatcher = RotationWatcher()
|
||||
|
||||
private var isNaturalRotation: Boolean = false
|
||||
|
||||
fun init() {
|
||||
try {
|
||||
windowManagerInterface.watchRotation(rotationWatcher, context.display.displayId)
|
||||
} catch (e: RemoteException) {
|
||||
throw e.rethrowFromSystemServer()
|
||||
}
|
||||
|
||||
onRotationChanged(context.display.rotation)
|
||||
}
|
||||
|
||||
private fun onRotationChanged(rotation: Int) {
|
||||
val isNewRotationNatural = rotation == Surface.ROTATION_0 ||
|
||||
rotation == Surface.ROTATION_180
|
||||
|
||||
if (isNaturalRotation != isNewRotationNatural) {
|
||||
isNaturalRotation = isNewRotationNatural
|
||||
scopedUnfoldTransitionProgressProvider.setReadyToHandleTransition(isNewRotationNatural)
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
try {
|
||||
windowManagerInterface.removeRotationWatcher(rotationWatcher)
|
||||
} catch (e: RemoteException) {
|
||||
e.rethrowFromSystemServer()
|
||||
}
|
||||
|
||||
scopedUnfoldTransitionProgressProvider.destroy()
|
||||
}
|
||||
|
||||
override fun addCallback(listener: TransitionProgressListener) {
|
||||
scopedUnfoldTransitionProgressProvider.addCallback(listener)
|
||||
}
|
||||
|
||||
override fun removeCallback(listener: TransitionProgressListener) {
|
||||
scopedUnfoldTransitionProgressProvider.removeCallback(listener)
|
||||
}
|
||||
|
||||
private inner class RotationWatcher : IRotationWatcher.Stub() {
|
||||
override fun onRotationChanged(rotation: Int) {
|
||||
this@NaturalRotationUnfoldProgressProvider.onRotationChanged(rotation)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.unfold.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manages progress listeners that can have smaller lifespan than the unfold animation.
|
||||
* Allows to limit getting transition updates to only when
|
||||
* {@link ScopedUnfoldTransitionProgressProvider#setReadyToHandleTransition} is called
|
||||
* with readyToHandleTransition = true
|
||||
*
|
||||
* If the transition has already started by the moment when the clients are ready to play
|
||||
* the transition then it will report transition started callback and current animation progress.
|
||||
*/
|
||||
public final class ScopedUnfoldTransitionProgressProvider implements
|
||||
UnfoldTransitionProgressProvider, TransitionProgressListener {
|
||||
|
||||
private static final float PROGRESS_UNSET = -1f;
|
||||
|
||||
@Nullable
|
||||
private UnfoldTransitionProgressProvider mSource;
|
||||
|
||||
private final List<TransitionProgressListener> mListeners = new ArrayList<>();
|
||||
|
||||
private boolean mIsReadyToHandleTransition;
|
||||
private boolean mIsTransitionRunning;
|
||||
private float mLastTransitionProgress = PROGRESS_UNSET;
|
||||
|
||||
public ScopedUnfoldTransitionProgressProvider() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public ScopedUnfoldTransitionProgressProvider(
|
||||
@Nullable UnfoldTransitionProgressProvider source) {
|
||||
setSourceProvider(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source for the unfold transition progress updates,
|
||||
* it replaces current provider if it is already set
|
||||
* @param provider transition provider that emits transition progress updates
|
||||
*/
|
||||
public void setSourceProvider(@Nullable UnfoldTransitionProgressProvider provider) {
|
||||
if (mSource != null) {
|
||||
mSource.removeCallback(this);
|
||||
}
|
||||
|
||||
if (provider != null) {
|
||||
mSource = provider;
|
||||
mSource.addCallback(this);
|
||||
} else {
|
||||
mSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to notify this provide whether the listeners can play the transition or not.
|
||||
* Call this method with readyToHandleTransition = true when all listeners
|
||||
* are ready to consume the transition progress events.
|
||||
* Call it with readyToHandleTransition = false when listeners can't process the events.
|
||||
*/
|
||||
public void setReadyToHandleTransition(boolean isReadyToHandleTransition) {
|
||||
if (mIsTransitionRunning) {
|
||||
if (isReadyToHandleTransition) {
|
||||
mListeners.forEach(TransitionProgressListener::onTransitionStarted);
|
||||
|
||||
if (mLastTransitionProgress != PROGRESS_UNSET) {
|
||||
mListeners.forEach(listener ->
|
||||
listener.onTransitionProgress(mLastTransitionProgress));
|
||||
}
|
||||
} else {
|
||||
mIsTransitionRunning = false;
|
||||
mListeners.forEach(TransitionProgressListener::onTransitionFinished);
|
||||
}
|
||||
}
|
||||
|
||||
mIsReadyToHandleTransition = isReadyToHandleTransition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(@NonNull TransitionProgressListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCallback(@NonNull TransitionProgressListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
mSource.removeCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionStarted() {
|
||||
this.mIsTransitionRunning = true;
|
||||
if (mIsReadyToHandleTransition) {
|
||||
mListeners.forEach(TransitionProgressListener::onTransitionStarted);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionProgress(float progress) {
|
||||
if (mIsReadyToHandleTransition) {
|
||||
mListeners.forEach(listener -> listener.onTransitionProgress(progress));
|
||||
}
|
||||
|
||||
mLastTransitionProgress = progress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionFinished() {
|
||||
if (mIsReadyToHandleTransition) {
|
||||
mListeners.forEach(TransitionProgressListener::onTransitionFinished);
|
||||
}
|
||||
|
||||
mIsTransitionRunning = false;
|
||||
mLastTransitionProgress = PROGRESS_UNSET;
|
||||
}
|
||||
}
|
||||
@@ -18,25 +18,28 @@ package com.android.systemui.statusbar.phone
|
||||
import android.graphics.Point
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
|
||||
import com.android.systemui.statusbar.CommandQueue
|
||||
import com.android.systemui.unfold.UNFOLD_STATUS_BAR
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
|
||||
import com.android.systemui.util.ViewController
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
import dagger.Lazy
|
||||
|
||||
/** Controller for [PhoneStatusBarView]. */
|
||||
class PhoneStatusBarViewController(
|
||||
class PhoneStatusBarViewController private constructor(
|
||||
view: PhoneStatusBarView,
|
||||
statusBarMoveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
|
||||
@Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
|
||||
private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
|
||||
touchEventHandler: PhoneStatusBarView.TouchEventHandler,
|
||||
) : ViewController<PhoneStatusBarView>(view) {
|
||||
|
||||
override fun onViewAttached() {}
|
||||
override fun onViewDetached() {}
|
||||
|
||||
init {
|
||||
mView.setTouchEventHandler(touchEventHandler)
|
||||
|
||||
statusBarMoveFromCenterAnimationController?.let { animationController ->
|
||||
override fun onViewAttached() {
|
||||
moveFromCenterAnimationController?.let { animationController ->
|
||||
val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side)
|
||||
val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area)
|
||||
|
||||
@@ -46,15 +49,33 @@ class PhoneStatusBarViewController(
|
||||
systemIconArea
|
||||
)
|
||||
|
||||
animationController.init(viewsToAnimate, viewCenterProvider)
|
||||
mView.viewTreeObserver.addOnPreDrawListener(object :
|
||||
ViewTreeObserver.OnPreDrawListener {
|
||||
override fun onPreDraw(): Boolean {
|
||||
animationController.onViewsReady(viewsToAnimate, viewCenterProvider)
|
||||
mView.viewTreeObserver.removeOnPreDrawListener(this)
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
|
||||
val widthChanged = right - left != oldRight - oldLeft
|
||||
if (widthChanged) {
|
||||
statusBarMoveFromCenterAnimationController.onStatusBarWidthChanged()
|
||||
moveFromCenterAnimationController.onStatusBarWidthChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progressProvider?.setReadyToHandleTransition(true)
|
||||
}
|
||||
|
||||
override fun onViewDetached() {
|
||||
progressProvider?.setReadyToHandleTransition(false)
|
||||
moveFromCenterAnimationController?.onViewDetached()
|
||||
}
|
||||
|
||||
init {
|
||||
mView.setTouchEventHandler(touchEventHandler)
|
||||
}
|
||||
|
||||
fun setImportantForAccessibility(mode: Int) {
|
||||
@@ -92,4 +113,23 @@ class PhoneStatusBarViewController(
|
||||
outPoint.y = viewY + view.height / 2
|
||||
}
|
||||
}
|
||||
|
||||
class Factory @Inject constructor(
|
||||
@Named(UNFOLD_STATUS_BAR)
|
||||
private val progressProvider: Lazy<ScopedUnfoldTransitionProgressProvider>,
|
||||
private val moveFromCenterController: Lazy<StatusBarMoveFromCenterAnimationController>,
|
||||
private val unfoldConfig: UnfoldTransitionConfig,
|
||||
) {
|
||||
fun create(
|
||||
view: PhoneStatusBarView,
|
||||
touchEventHandler: PhoneStatusBarView.TouchEventHandler
|
||||
): PhoneStatusBarViewController {
|
||||
return PhoneStatusBarViewController(
|
||||
view,
|
||||
if (unfoldConfig.isEnabled) progressProvider.get() else null,
|
||||
if (unfoldConfig.isEnabled) moveFromCenterController.get() else null,
|
||||
touchEventHandler
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,6 +233,7 @@ import com.android.systemui.tuner.TunerService;
|
||||
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
|
||||
import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
|
||||
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
|
||||
import com.android.systemui.util.WallpaperController;
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||
import com.android.systemui.util.concurrency.MessageRouter;
|
||||
@@ -525,6 +526,7 @@ public class StatusBar extends SystemUI implements
|
||||
private QSPanelController mQSPanelController;
|
||||
|
||||
private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
|
||||
private final PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory;
|
||||
KeyguardIndicationController mKeyguardIndicationController;
|
||||
|
||||
private View mReportRejectedTouch;
|
||||
@@ -543,8 +545,8 @@ public class StatusBar extends SystemUI implements
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
private final UnfoldTransitionConfig mUnfoldTransitionConfig;
|
||||
private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation;
|
||||
private final Lazy<NaturalRotationUnfoldProgressProvider> mNaturalUnfoldProgressProvider;
|
||||
private final Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController;
|
||||
private final Lazy<StatusBarMoveFromCenterAnimationController> mMoveFromCenterAnimation;
|
||||
private final WallpaperController mWallpaperController;
|
||||
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||
private final MessageRouter mMessageRouter;
|
||||
@@ -772,6 +774,7 @@ public class StatusBar extends SystemUI implements
|
||||
ExtensionController extensionController,
|
||||
UserInfoControllerImpl userInfoControllerImpl,
|
||||
OperatorNameViewController.Factory operatorNameViewControllerFactory,
|
||||
PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory,
|
||||
PhoneStatusBarPolicy phoneStatusBarPolicy,
|
||||
KeyguardIndicationController keyguardIndicationController,
|
||||
DemoModeController demoModeController,
|
||||
@@ -782,7 +785,7 @@ public class StatusBar extends SystemUI implements
|
||||
UnfoldTransitionConfig unfoldTransitionConfig,
|
||||
Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
|
||||
Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController,
|
||||
Lazy<StatusBarMoveFromCenterAnimationController> statusBarUnfoldAnimationController,
|
||||
Lazy<NaturalRotationUnfoldProgressProvider> naturalRotationUnfoldProgressProvider,
|
||||
WallpaperController wallpaperController,
|
||||
OngoingCallController ongoingCallController,
|
||||
SystemStatusAnimationScheduler animationScheduler,
|
||||
@@ -812,6 +815,7 @@ public class StatusBar extends SystemUI implements
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mHeadsUpManager = headsUpManagerPhone;
|
||||
mOperatorNameViewControllerFactory = operatorNameViewControllerFactory;
|
||||
mPhoneStatusBarViewControllerFactory = phoneStatusBarViewControllerFactory;
|
||||
mKeyguardIndicationController = keyguardIndicationController;
|
||||
mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
|
||||
mDynamicPrivacyController = dynamicPrivacyController;
|
||||
@@ -879,9 +883,9 @@ public class StatusBar extends SystemUI implements
|
||||
mBrightnessSliderFactory = brightnessSliderFactory;
|
||||
mUnfoldTransitionConfig = unfoldTransitionConfig;
|
||||
mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation;
|
||||
mNaturalUnfoldProgressProvider = naturalRotationUnfoldProgressProvider;
|
||||
mUnfoldWallpaperController = unfoldTransitionWallpaperController;
|
||||
mWallpaperController = wallpaperController;
|
||||
mMoveFromCenterAnimation = statusBarUnfoldAnimationController;
|
||||
mOngoingCallController = ongoingCallController;
|
||||
mAnimationScheduler = animationScheduler;
|
||||
mStatusBarLocationPublisher = locationPublisher;
|
||||
@@ -1077,6 +1081,7 @@ public class StatusBar extends SystemUI implements
|
||||
if (mUnfoldTransitionConfig.isEnabled()) {
|
||||
mUnfoldLightRevealOverlayAnimation.get().init();
|
||||
mUnfoldWallpaperController.get().init();
|
||||
mNaturalUnfoldProgressProvider.get().init();
|
||||
}
|
||||
|
||||
mPluginManager.addPluginListener(
|
||||
@@ -1178,16 +1183,9 @@ public class StatusBar extends SystemUI implements
|
||||
|
||||
mNotificationPanelViewController.setBar(mStatusBarView);
|
||||
|
||||
StatusBarMoveFromCenterAnimationController moveFromCenterAnimation = null;
|
||||
if (mUnfoldTransitionConfig.isEnabled()) {
|
||||
moveFromCenterAnimation = mMoveFromCenterAnimation.get();
|
||||
}
|
||||
mPhoneStatusBarViewController =
|
||||
new PhoneStatusBarViewController(
|
||||
mStatusBarView,
|
||||
moveFromCenterAnimation,
|
||||
mNotificationPanelViewController.getStatusBarTouchEventHandler()
|
||||
);
|
||||
mPhoneStatusBarViewController = mPhoneStatusBarViewControllerFactory
|
||||
.create(mStatusBarView, mNotificationPanelViewController
|
||||
.getStatusBarTouchEventHandler());
|
||||
mPhoneStatusBarViewController.init();
|
||||
|
||||
mBatteryMeterViewController = new BatteryMeterViewController(
|
||||
|
||||
@@ -20,43 +20,48 @@ import android.view.WindowManager
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
|
||||
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.ViewCenterProvider
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
|
||||
import com.android.systemui.unfold.UNFOLD_STATUS_BAR
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
@SysUISingleton
|
||||
class StatusBarMoveFromCenterAnimationController @Inject constructor(
|
||||
private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
|
||||
private val windowManager: WindowManager
|
||||
@Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider,
|
||||
private val windowManager: WindowManager,
|
||||
) {
|
||||
|
||||
private lateinit var moveFromCenterAnimator: UnfoldMoveFromCenterAnimator
|
||||
private val transitionListener = TransitionListener()
|
||||
private var moveFromCenterAnimator: UnfoldMoveFromCenterAnimator? = null
|
||||
|
||||
fun init(viewsToAnimate: Array<View>, viewCenterProvider: ViewCenterProvider) {
|
||||
fun onViewsReady(viewsToAnimate: Array<View>, viewCenterProvider: ViewCenterProvider) {
|
||||
moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(windowManager,
|
||||
viewCenterProvider = viewCenterProvider)
|
||||
|
||||
unfoldTransitionProgressProvider.addCallback(object : TransitionProgressListener {
|
||||
override fun onTransitionStarted() {
|
||||
moveFromCenterAnimator.updateDisplayProperties()
|
||||
moveFromCenterAnimator?.updateDisplayProperties()
|
||||
|
||||
viewsToAnimate.forEach {
|
||||
moveFromCenterAnimator.registerViewForAnimation(it)
|
||||
}
|
||||
}
|
||||
viewsToAnimate.forEach {
|
||||
moveFromCenterAnimator?.registerViewForAnimation(it)
|
||||
}
|
||||
|
||||
override fun onTransitionFinished() {
|
||||
moveFromCenterAnimator.onTransitionFinished()
|
||||
moveFromCenterAnimator.clearRegisteredViews()
|
||||
}
|
||||
progressProvider.addCallback(transitionListener)
|
||||
}
|
||||
|
||||
override fun onTransitionProgress(progress: Float) {
|
||||
moveFromCenterAnimator.onTransitionProgress(progress)
|
||||
}
|
||||
})
|
||||
fun onViewDetached() {
|
||||
progressProvider.removeCallback(transitionListener)
|
||||
moveFromCenterAnimator?.clearRegisteredViews()
|
||||
moveFromCenterAnimator = null
|
||||
}
|
||||
|
||||
fun onStatusBarWidthChanged() {
|
||||
moveFromCenterAnimator.updateViewPositions()
|
||||
moveFromCenterAnimator?.updateDisplayProperties()
|
||||
moveFromCenterAnimator?.updateViewPositions()
|
||||
}
|
||||
|
||||
private inner class TransitionListener : TransitionProgressListener {
|
||||
override fun onTransitionProgress(progress: Float) {
|
||||
moveFromCenterAnimator?.onTransitionProgress(progress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
|
||||
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
|
||||
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
|
||||
import com.android.systemui.statusbar.phone.ScrimController;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
@@ -111,6 +112,7 @@ import com.android.systemui.tuner.TunerService;
|
||||
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
|
||||
import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
|
||||
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
|
||||
import com.android.systemui.util.WallpaperController;
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||
import com.android.systemui.util.concurrency.MessageRouter;
|
||||
@@ -211,6 +213,7 @@ public interface StatusBarPhoneModule {
|
||||
ExtensionController extensionController,
|
||||
UserInfoControllerImpl userInfoControllerImpl,
|
||||
OperatorNameViewController.Factory operatorNameViewControllerFactory,
|
||||
PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory,
|
||||
PhoneStatusBarPolicy phoneStatusBarPolicy,
|
||||
KeyguardIndicationController keyguardIndicationController,
|
||||
DemoModeController demoModeController,
|
||||
@@ -220,6 +223,7 @@ public interface StatusBarPhoneModule {
|
||||
BrightnessSlider.Factory brightnessSliderFactory,
|
||||
UnfoldTransitionConfig unfoldTransitionConfig,
|
||||
Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
|
||||
Lazy<NaturalRotationUnfoldProgressProvider> naturalRotationUnfoldProgressProvider,
|
||||
Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController,
|
||||
Lazy<StatusBarMoveFromCenterAnimationController> statusBarMoveFromCenterAnimation,
|
||||
WallpaperController wallpaperController,
|
||||
@@ -311,6 +315,7 @@ public interface StatusBarPhoneModule {
|
||||
extensionController,
|
||||
userInfoControllerImpl,
|
||||
operatorNameViewControllerFactory,
|
||||
phoneStatusBarViewControllerFactory,
|
||||
phoneStatusBarPolicy,
|
||||
keyguardIndicationController,
|
||||
demoModeController,
|
||||
@@ -321,7 +326,7 @@ public interface StatusBarPhoneModule {
|
||||
unfoldTransitionConfig,
|
||||
unfoldLightRevealOverlayAnimation,
|
||||
unfoldTransitionWallpaperController,
|
||||
statusBarMoveFromCenterAnimation,
|
||||
naturalRotationUnfoldProgressProvider,
|
||||
wallpaperController,
|
||||
ongoingCallController,
|
||||
animationScheduler,
|
||||
|
||||
@@ -20,15 +20,19 @@ import android.content.Context
|
||||
import android.hardware.SensorManager
|
||||
import android.hardware.devicestate.DeviceStateManager
|
||||
import android.os.Handler
|
||||
import android.view.IWindowManager
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.keyguard.LifecycleScreenStatusProvider
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig
|
||||
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
|
||||
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider
|
||||
import dagger.Lazy
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Named
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@@ -60,6 +64,27 @@ class UnfoldTransitionModule {
|
||||
fun provideUnfoldTransitionConfig(context: Context): UnfoldTransitionConfig =
|
||||
createConfig(context)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideNaturalRotationProgressProvider(
|
||||
context: Context,
|
||||
windowManager: IWindowManager,
|
||||
unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider
|
||||
): NaturalRotationUnfoldProgressProvider =
|
||||
NaturalRotationUnfoldProgressProvider(
|
||||
context,
|
||||
windowManager,
|
||||
unfoldTransitionProgressProvider
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Named(UNFOLD_STATUS_BAR)
|
||||
@Singleton
|
||||
fun provideStatusBarScopedTransitionProvider(
|
||||
source: NaturalRotationUnfoldProgressProvider
|
||||
): ScopedUnfoldTransitionProgressProvider =
|
||||
ScopedUnfoldTransitionProgressProvider(source)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideShellProgressProvider(
|
||||
@@ -72,3 +97,5 @@ class UnfoldTransitionModule {
|
||||
Optional.empty()
|
||||
}
|
||||
}
|
||||
|
||||
const val UNFOLD_STATUS_BAR = "unfold_status_bar"
|
||||
@@ -19,19 +19,25 @@ package com.android.systemui.statusbar.phone
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.view.ViewTreeObserver.OnPreDrawListener
|
||||
import android.widget.FrameLayout
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.spy
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@@ -48,10 +54,14 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
|
||||
|
||||
@Mock
|
||||
private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController
|
||||
@Mock
|
||||
private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider
|
||||
|
||||
private lateinit var view: PhoneStatusBarView
|
||||
private lateinit var controller: PhoneStatusBarViewController
|
||||
|
||||
private val unfoldConfig = UnfoldConfig()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
@@ -66,11 +76,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
|
||||
view.setBar(mock(StatusBar::class.java))
|
||||
}
|
||||
|
||||
controller = PhoneStatusBarViewController(
|
||||
view,
|
||||
null,
|
||||
touchEventHandler,
|
||||
)
|
||||
controller = createController(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -83,12 +89,38 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun constructor_moveFromCenterAnimationIsNotNull_moveFromCenterAnimationInitialized() {
|
||||
controller = PhoneStatusBarViewController(
|
||||
view, moveFromCenterAnimation, touchEventHandler
|
||||
)
|
||||
fun onViewAttachedAndDrawn_moveFromCenterAnimationEnabled_moveFromCenterAnimationInitialized() {
|
||||
val view = createViewMock()
|
||||
val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
|
||||
unfoldConfig.isEnabled = true
|
||||
controller = createController(view)
|
||||
controller.init()
|
||||
|
||||
verify(moveFromCenterAnimation).init(any(), any())
|
||||
verify(view.viewTreeObserver).addOnPreDrawListener(argumentCaptor.capture())
|
||||
argumentCaptor.value.onPreDraw()
|
||||
|
||||
verify(moveFromCenterAnimation).onViewsReady(any(), any())
|
||||
}
|
||||
|
||||
private fun createViewMock(): PhoneStatusBarView {
|
||||
val view = spy(view)
|
||||
val viewTreeObserver = mock(ViewTreeObserver::class.java)
|
||||
`when`(view.viewTreeObserver).thenReturn(viewTreeObserver)
|
||||
`when`(view.isAttachedToWindow).thenReturn(true)
|
||||
return view
|
||||
}
|
||||
|
||||
private fun createController(view: PhoneStatusBarView): PhoneStatusBarViewController {
|
||||
return PhoneStatusBarViewController.Factory(
|
||||
{ progressProvider },
|
||||
{ moveFromCenterAnimation },
|
||||
unfoldConfig
|
||||
).create(view, touchEventHandler)
|
||||
}
|
||||
|
||||
private class UnfoldConfig : UnfoldTransitionConfig {
|
||||
override var isEnabled: Boolean = false
|
||||
override var isHingeAngleEnabled: Boolean = false
|
||||
}
|
||||
|
||||
private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
|
||||
@@ -97,6 +129,5 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
|
||||
lastEvent = event
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ import com.android.systemui.tuner.TunerService;
|
||||
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
|
||||
import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
|
||||
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
|
||||
import com.android.systemui.util.WallpaperController;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.concurrency.MessageRouterImpl;
|
||||
@@ -259,7 +260,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
@Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
|
||||
@Mock private UnfoldTransitionConfig mUnfoldTransitionConfig;
|
||||
@Mock private Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimationLazy;
|
||||
@Mock private Lazy<StatusBarMoveFromCenterAnimationController> mMoveFromCenterAnimationLazy;
|
||||
@Mock private Lazy<NaturalRotationUnfoldProgressProvider> mNaturalRotationProgressProvider;
|
||||
@Mock private Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController;
|
||||
@Mock private WallpaperController mWallpaperController;
|
||||
@Mock private OngoingCallController mOngoingCallController;
|
||||
@@ -276,6 +277,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
@Mock private StartingSurface mStartingSurface;
|
||||
@Mock private OperatorNameViewController mOperatorNameViewController;
|
||||
@Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
|
||||
@Mock private PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory;
|
||||
@Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
@Mock private DialogLaunchAnimator mDialogLaunchAnimator;
|
||||
private ShadeController mShadeController;
|
||||
@@ -430,6 +432,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
mExtensionController,
|
||||
mUserInfoControllerImpl,
|
||||
mOperatorNameViewControllerFactory,
|
||||
mPhoneStatusBarViewControllerFactory,
|
||||
mPhoneStatusBarPolicy,
|
||||
mKeyguardIndicationController,
|
||||
mDemoModeController,
|
||||
@@ -440,7 +443,7 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
mUnfoldTransitionConfig,
|
||||
mUnfoldLightRevealOverlayAnimationLazy,
|
||||
mUnfoldWallpaperController,
|
||||
mMoveFromCenterAnimationLazy,
|
||||
mNaturalRotationProgressProvider,
|
||||
mWallpaperController,
|
||||
mOngoingCallController,
|
||||
mAnimationScheduler,
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.unfold.util
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.view.IRotationWatcher
|
||||
import android.view.IWindowManager
|
||||
import android.view.Surface
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
|
||||
|
||||
@Mock
|
||||
lateinit var windowManager: IWindowManager
|
||||
|
||||
@Mock
|
||||
lateinit var sourceProvider: UnfoldTransitionProgressProvider
|
||||
|
||||
@Mock
|
||||
lateinit var transitionListener: TransitionProgressListener
|
||||
|
||||
lateinit var progressProvider: NaturalRotationUnfoldProgressProvider
|
||||
|
||||
private val sourceProviderListenerCaptor =
|
||||
ArgumentCaptor.forClass(TransitionProgressListener::class.java)
|
||||
private val rotationWatcherCaptor =
|
||||
ArgumentCaptor.forClass(IRotationWatcher.Stub::class.java)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
progressProvider = NaturalRotationUnfoldProgressProvider(
|
||||
context,
|
||||
windowManager,
|
||||
sourceProvider
|
||||
)
|
||||
|
||||
progressProvider.init()
|
||||
|
||||
verify(sourceProvider).addCallback(sourceProviderListenerCaptor.capture())
|
||||
verify(windowManager).watchRotation(rotationWatcherCaptor.capture(), any())
|
||||
|
||||
progressProvider.addCallback(transitionListener)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNaturalRotation0_sendTransitionStartedEvent_eventReceived() {
|
||||
onRotationChanged(Surface.ROTATION_0)
|
||||
|
||||
source.onTransitionStarted()
|
||||
|
||||
verify(transitionListener).onTransitionStarted()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNaturalRotation0_sendTransitionProgressEvent_eventReceived() {
|
||||
onRotationChanged(Surface.ROTATION_0)
|
||||
|
||||
source.onTransitionProgress(0.5f)
|
||||
|
||||
verify(transitionListener).onTransitionProgress(0.5f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNotNaturalRotation90_sendTransitionStartedEvent_eventNotReceived() {
|
||||
onRotationChanged(Surface.ROTATION_90)
|
||||
|
||||
source.onTransitionStarted()
|
||||
|
||||
verify(transitionListener, never()).onTransitionStarted()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNaturalRotation90_sendTransitionProgressEvent_eventNotReceived() {
|
||||
onRotationChanged(Surface.ROTATION_90)
|
||||
|
||||
source.onTransitionProgress(0.5f)
|
||||
|
||||
verify(transitionListener, never()).onTransitionProgress(0.5f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRotationBecameUnnaturalDuringTransition_sendsTransitionFinishedEvent() {
|
||||
onRotationChanged(Surface.ROTATION_0)
|
||||
source.onTransitionStarted()
|
||||
clearInvocations(transitionListener)
|
||||
|
||||
onRotationChanged(Surface.ROTATION_90)
|
||||
|
||||
verify(transitionListener).onTransitionFinished()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRotationBecameNaturalDuringTransition_sendsTransitionStartedEvent() {
|
||||
onRotationChanged(Surface.ROTATION_90)
|
||||
source.onTransitionStarted()
|
||||
clearInvocations(transitionListener)
|
||||
|
||||
onRotationChanged(Surface.ROTATION_0)
|
||||
|
||||
verify(transitionListener).onTransitionStarted()
|
||||
}
|
||||
|
||||
private fun onRotationChanged(rotation: Int) {
|
||||
rotationWatcherCaptor.value.onRotationChanged(rotation)
|
||||
}
|
||||
|
||||
private val source: TransitionProgressListener
|
||||
get() = sourceProviderListenerCaptor.value
|
||||
}
|
||||
Reference in New Issue
Block a user