Merge "Do not animate statusbar unfold when in portrait orientation" into sc-v2-dev

This commit is contained in:
Nick Chameyev
2021-10-21 10:02:00 +00:00
committed by Android (Google) Code Review
10 changed files with 523 additions and 60 deletions

View File

@@ -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)
}
}
}

View File

@@ -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;
}
}

View File

@@ -18,25 +18,28 @@ package com.android.systemui.statusbar.phone
import android.graphics.Point import android.graphics.Point
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
import com.android.systemui.statusbar.CommandQueue 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 com.android.systemui.util.ViewController
import javax.inject.Inject
import javax.inject.Named
import dagger.Lazy
/** Controller for [PhoneStatusBarView]. */ /** Controller for [PhoneStatusBarView]. */
class PhoneStatusBarViewController( class PhoneStatusBarViewController private constructor(
view: PhoneStatusBarView, view: PhoneStatusBarView,
statusBarMoveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?, @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
touchEventHandler: PhoneStatusBarView.TouchEventHandler, touchEventHandler: PhoneStatusBarView.TouchEventHandler,
) : ViewController<PhoneStatusBarView>(view) { ) : ViewController<PhoneStatusBarView>(view) {
override fun onViewAttached() {} override fun onViewAttached() {
override fun onViewDetached() {} moveFromCenterAnimationController?.let { animationController ->
init {
mView.setTouchEventHandler(touchEventHandler)
statusBarMoveFromCenterAnimationController?.let { animationController ->
val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side) val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side)
val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area) val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area)
@@ -46,15 +49,33 @@ class PhoneStatusBarViewController(
systemIconArea 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, _ -> mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
val widthChanged = right - left != oldRight - oldLeft val widthChanged = right - left != oldRight - oldLeft
if (widthChanged) { 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) { fun setImportantForAccessibility(mode: Int) {
@@ -92,4 +113,23 @@ class PhoneStatusBarViewController(
outPoint.y = viewY + view.height / 2 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
)
}
}
} }

View File

@@ -233,6 +233,7 @@ import com.android.systemui.tuner.TunerService;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.unfold.UnfoldTransitionWallpaperController; import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
import com.android.systemui.unfold.config.UnfoldTransitionConfig; 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.WallpaperController;
import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.MessageRouter; import com.android.systemui.util.concurrency.MessageRouter;
@@ -525,6 +526,7 @@ public class StatusBar extends SystemUI implements
private QSPanelController mQSPanelController; private QSPanelController mQSPanelController;
private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory; private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
private final PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory;
KeyguardIndicationController mKeyguardIndicationController; KeyguardIndicationController mKeyguardIndicationController;
private View mReportRejectedTouch; private View mReportRejectedTouch;
@@ -543,8 +545,8 @@ public class StatusBar extends SystemUI implements
private final FeatureFlags mFeatureFlags; private final FeatureFlags mFeatureFlags;
private final UnfoldTransitionConfig mUnfoldTransitionConfig; private final UnfoldTransitionConfig mUnfoldTransitionConfig;
private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation; private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation;
private final Lazy<NaturalRotationUnfoldProgressProvider> mNaturalUnfoldProgressProvider;
private final Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController; private final Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController;
private final Lazy<StatusBarMoveFromCenterAnimationController> mMoveFromCenterAnimation;
private final WallpaperController mWallpaperController; private final WallpaperController mWallpaperController;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final MessageRouter mMessageRouter; private final MessageRouter mMessageRouter;
@@ -772,6 +774,7 @@ public class StatusBar extends SystemUI implements
ExtensionController extensionController, ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl, UserInfoControllerImpl userInfoControllerImpl,
OperatorNameViewController.Factory operatorNameViewControllerFactory, OperatorNameViewController.Factory operatorNameViewControllerFactory,
PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory,
PhoneStatusBarPolicy phoneStatusBarPolicy, PhoneStatusBarPolicy phoneStatusBarPolicy,
KeyguardIndicationController keyguardIndicationController, KeyguardIndicationController keyguardIndicationController,
DemoModeController demoModeController, DemoModeController demoModeController,
@@ -782,7 +785,7 @@ public class StatusBar extends SystemUI implements
UnfoldTransitionConfig unfoldTransitionConfig, UnfoldTransitionConfig unfoldTransitionConfig,
Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation, Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController, Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController,
Lazy<StatusBarMoveFromCenterAnimationController> statusBarUnfoldAnimationController, Lazy<NaturalRotationUnfoldProgressProvider> naturalRotationUnfoldProgressProvider,
WallpaperController wallpaperController, WallpaperController wallpaperController,
OngoingCallController ongoingCallController, OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler, SystemStatusAnimationScheduler animationScheduler,
@@ -812,6 +815,7 @@ public class StatusBar extends SystemUI implements
mKeyguardStateController = keyguardStateController; mKeyguardStateController = keyguardStateController;
mHeadsUpManager = headsUpManagerPhone; mHeadsUpManager = headsUpManagerPhone;
mOperatorNameViewControllerFactory = operatorNameViewControllerFactory; mOperatorNameViewControllerFactory = operatorNameViewControllerFactory;
mPhoneStatusBarViewControllerFactory = phoneStatusBarViewControllerFactory;
mKeyguardIndicationController = keyguardIndicationController; mKeyguardIndicationController = keyguardIndicationController;
mStatusBarTouchableRegionManager = statusBarTouchableRegionManager; mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
mDynamicPrivacyController = dynamicPrivacyController; mDynamicPrivacyController = dynamicPrivacyController;
@@ -879,9 +883,9 @@ public class StatusBar extends SystemUI implements
mBrightnessSliderFactory = brightnessSliderFactory; mBrightnessSliderFactory = brightnessSliderFactory;
mUnfoldTransitionConfig = unfoldTransitionConfig; mUnfoldTransitionConfig = unfoldTransitionConfig;
mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation; mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation;
mNaturalUnfoldProgressProvider = naturalRotationUnfoldProgressProvider;
mUnfoldWallpaperController = unfoldTransitionWallpaperController; mUnfoldWallpaperController = unfoldTransitionWallpaperController;
mWallpaperController = wallpaperController; mWallpaperController = wallpaperController;
mMoveFromCenterAnimation = statusBarUnfoldAnimationController;
mOngoingCallController = ongoingCallController; mOngoingCallController = ongoingCallController;
mAnimationScheduler = animationScheduler; mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher; mStatusBarLocationPublisher = locationPublisher;
@@ -1077,6 +1081,7 @@ public class StatusBar extends SystemUI implements
if (mUnfoldTransitionConfig.isEnabled()) { if (mUnfoldTransitionConfig.isEnabled()) {
mUnfoldLightRevealOverlayAnimation.get().init(); mUnfoldLightRevealOverlayAnimation.get().init();
mUnfoldWallpaperController.get().init(); mUnfoldWallpaperController.get().init();
mNaturalUnfoldProgressProvider.get().init();
} }
mPluginManager.addPluginListener( mPluginManager.addPluginListener(
@@ -1178,16 +1183,9 @@ public class StatusBar extends SystemUI implements
mNotificationPanelViewController.setBar(mStatusBarView); mNotificationPanelViewController.setBar(mStatusBarView);
StatusBarMoveFromCenterAnimationController moveFromCenterAnimation = null; mPhoneStatusBarViewController = mPhoneStatusBarViewControllerFactory
if (mUnfoldTransitionConfig.isEnabled()) { .create(mStatusBarView, mNotificationPanelViewController
moveFromCenterAnimation = mMoveFromCenterAnimation.get(); .getStatusBarTouchEventHandler());
}
mPhoneStatusBarViewController =
new PhoneStatusBarViewController(
mStatusBarView,
moveFromCenterAnimation,
mNotificationPanelViewController.getStatusBarTouchEventHandler()
);
mPhoneStatusBarViewController.init(); mPhoneStatusBarViewController.init();
mBatteryMeterViewController = new BatteryMeterViewController( mBatteryMeterViewController = new BatteryMeterViewController(

View File

@@ -20,43 +20,48 @@ import android.view.WindowManager
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.ViewCenterProvider 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.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Named
@SysUISingleton @SysUISingleton
class StatusBarMoveFromCenterAnimationController @Inject constructor( class StatusBarMoveFromCenterAnimationController @Inject constructor(
private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider, @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider,
private val windowManager: WindowManager 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, moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(windowManager,
viewCenterProvider = viewCenterProvider) viewCenterProvider = viewCenterProvider)
unfoldTransitionProgressProvider.addCallback(object : TransitionProgressListener { moveFromCenterAnimator?.updateDisplayProperties()
override fun onTransitionStarted() {
moveFromCenterAnimator.updateDisplayProperties()
viewsToAnimate.forEach { viewsToAnimate.forEach {
moveFromCenterAnimator.registerViewForAnimation(it) moveFromCenterAnimator?.registerViewForAnimation(it)
}
} }
override fun onTransitionFinished() { progressProvider.addCallback(transitionListener)
moveFromCenterAnimator.onTransitionFinished()
moveFromCenterAnimator.clearRegisteredViews()
} }
override fun onTransitionProgress(progress: Float) { fun onViewDetached() {
moveFromCenterAnimator.onTransitionProgress(progress) progressProvider.removeCallback(transitionListener)
} moveFromCenterAnimator?.clearRegisteredViews()
}) moveFromCenterAnimator = null
} }
fun onStatusBarWidthChanged() { fun onStatusBarWidthChanged() {
moveFromCenterAnimator.updateViewPositions() moveFromCenterAnimator?.updateDisplayProperties()
moveFromCenterAnimator?.updateViewPositions()
}
private inner class TransitionListener : TransitionProgressListener {
override fun onTransitionProgress(progress: Float) {
moveFromCenterAnimator?.onTransitionProgress(progress)
}
} }
} }

View File

@@ -88,6 +88,7 @@ import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; 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.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar; 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.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.unfold.UnfoldTransitionWallpaperController; import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
import com.android.systemui.unfold.config.UnfoldTransitionConfig; 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.WallpaperController;
import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.MessageRouter; import com.android.systemui.util.concurrency.MessageRouter;
@@ -211,6 +213,7 @@ public interface StatusBarPhoneModule {
ExtensionController extensionController, ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl, UserInfoControllerImpl userInfoControllerImpl,
OperatorNameViewController.Factory operatorNameViewControllerFactory, OperatorNameViewController.Factory operatorNameViewControllerFactory,
PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory,
PhoneStatusBarPolicy phoneStatusBarPolicy, PhoneStatusBarPolicy phoneStatusBarPolicy,
KeyguardIndicationController keyguardIndicationController, KeyguardIndicationController keyguardIndicationController,
DemoModeController demoModeController, DemoModeController demoModeController,
@@ -220,6 +223,7 @@ public interface StatusBarPhoneModule {
BrightnessSlider.Factory brightnessSliderFactory, BrightnessSlider.Factory brightnessSliderFactory,
UnfoldTransitionConfig unfoldTransitionConfig, UnfoldTransitionConfig unfoldTransitionConfig,
Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation, Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
Lazy<NaturalRotationUnfoldProgressProvider> naturalRotationUnfoldProgressProvider,
Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController, Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController,
Lazy<StatusBarMoveFromCenterAnimationController> statusBarMoveFromCenterAnimation, Lazy<StatusBarMoveFromCenterAnimationController> statusBarMoveFromCenterAnimation,
WallpaperController wallpaperController, WallpaperController wallpaperController,
@@ -311,6 +315,7 @@ public interface StatusBarPhoneModule {
extensionController, extensionController,
userInfoControllerImpl, userInfoControllerImpl,
operatorNameViewControllerFactory, operatorNameViewControllerFactory,
phoneStatusBarViewControllerFactory,
phoneStatusBarPolicy, phoneStatusBarPolicy,
keyguardIndicationController, keyguardIndicationController,
demoModeController, demoModeController,
@@ -321,7 +326,7 @@ public interface StatusBarPhoneModule {
unfoldTransitionConfig, unfoldTransitionConfig,
unfoldLightRevealOverlayAnimation, unfoldLightRevealOverlayAnimation,
unfoldTransitionWallpaperController, unfoldTransitionWallpaperController,
statusBarMoveFromCenterAnimation, naturalRotationUnfoldProgressProvider,
wallpaperController, wallpaperController,
ongoingCallController, ongoingCallController,
animationScheduler, animationScheduler,

View File

@@ -20,15 +20,19 @@ import android.content.Context
import android.hardware.SensorManager import android.hardware.SensorManager
import android.hardware.devicestate.DeviceStateManager import android.hardware.devicestate.DeviceStateManager
import android.os.Handler import android.os.Handler
import android.view.IWindowManager
import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.LifecycleScreenStatusProvider import com.android.systemui.keyguard.LifecycleScreenStatusProvider
import com.android.systemui.unfold.config.UnfoldTransitionConfig 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 com.android.wm.shell.unfold.ShellUnfoldProgressProvider
import dagger.Lazy import dagger.Lazy
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import java.util.Optional import java.util.Optional
import java.util.concurrent.Executor import java.util.concurrent.Executor
import javax.inject.Named
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@@ -60,6 +64,27 @@ class UnfoldTransitionModule {
fun provideUnfoldTransitionConfig(context: Context): UnfoldTransitionConfig = fun provideUnfoldTransitionConfig(context: Context): UnfoldTransitionConfig =
createConfig(context) 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 @Provides
@Singleton @Singleton
fun provideShellProgressProvider( fun provideShellProgressProvider(
@@ -72,3 +97,5 @@ class UnfoldTransitionModule {
Optional.empty() Optional.empty()
} }
} }
const val UNFOLD_STATUS_BAR = "unfold_status_bar"

View File

@@ -19,19 +19,25 @@ package com.android.systemui.statusbar.phone
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent import android.view.MotionEvent
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.OnPreDrawListener
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.SysuiTestCase 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.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.mock
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@SmallTest @SmallTest
@@ -48,10 +54,14 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@Mock @Mock
private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController
@Mock
private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider
private lateinit var view: PhoneStatusBarView private lateinit var view: PhoneStatusBarView
private lateinit var controller: PhoneStatusBarViewController private lateinit var controller: PhoneStatusBarViewController
private val unfoldConfig = UnfoldConfig()
@Before @Before
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
@@ -66,11 +76,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
view.setBar(mock(StatusBar::class.java)) view.setBar(mock(StatusBar::class.java))
} }
controller = PhoneStatusBarViewController( controller = createController(view)
view,
null,
touchEventHandler,
)
} }
@Test @Test
@@ -83,12 +89,38 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
} }
@Test @Test
fun constructor_moveFromCenterAnimationIsNotNull_moveFromCenterAnimationInitialized() { fun onViewAttachedAndDrawn_moveFromCenterAnimationEnabled_moveFromCenterAnimationInitialized() {
controller = PhoneStatusBarViewController( val view = createViewMock()
view, moveFromCenterAnimation, touchEventHandler 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 { private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
@@ -97,6 +129,5 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
lastEvent = event lastEvent = event
return false return false
} }
} }
} }

View File

@@ -144,6 +144,7 @@ import com.android.systemui.tuner.TunerService;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.unfold.UnfoldTransitionWallpaperController; import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
import com.android.systemui.unfold.config.UnfoldTransitionConfig; 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.WallpaperController;
import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.concurrency.MessageRouterImpl; import com.android.systemui.util.concurrency.MessageRouterImpl;
@@ -259,7 +260,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private BrightnessSlider.Factory mBrightnessSliderFactory; @Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
@Mock private UnfoldTransitionConfig mUnfoldTransitionConfig; @Mock private UnfoldTransitionConfig mUnfoldTransitionConfig;
@Mock private Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimationLazy; @Mock private Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimationLazy;
@Mock private Lazy<StatusBarMoveFromCenterAnimationController> mMoveFromCenterAnimationLazy; @Mock private Lazy<NaturalRotationUnfoldProgressProvider> mNaturalRotationProgressProvider;
@Mock private Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController; @Mock private Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController;
@Mock private WallpaperController mWallpaperController; @Mock private WallpaperController mWallpaperController;
@Mock private OngoingCallController mOngoingCallController; @Mock private OngoingCallController mOngoingCallController;
@@ -276,6 +277,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private StartingSurface mStartingSurface; @Mock private StartingSurface mStartingSurface;
@Mock private OperatorNameViewController mOperatorNameViewController; @Mock private OperatorNameViewController mOperatorNameViewController;
@Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory; @Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
@Mock private PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory;
@Mock private ActivityLaunchAnimator mActivityLaunchAnimator; @Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
@Mock private DialogLaunchAnimator mDialogLaunchAnimator; @Mock private DialogLaunchAnimator mDialogLaunchAnimator;
private ShadeController mShadeController; private ShadeController mShadeController;
@@ -429,6 +431,7 @@ public class StatusBarTest extends SysuiTestCase {
mExtensionController, mExtensionController,
mUserInfoControllerImpl, mUserInfoControllerImpl,
mOperatorNameViewControllerFactory, mOperatorNameViewControllerFactory,
mPhoneStatusBarViewControllerFactory,
mPhoneStatusBarPolicy, mPhoneStatusBarPolicy,
mKeyguardIndicationController, mKeyguardIndicationController,
mDemoModeController, mDemoModeController,
@@ -439,7 +442,7 @@ public class StatusBarTest extends SysuiTestCase {
mUnfoldTransitionConfig, mUnfoldTransitionConfig,
mUnfoldLightRevealOverlayAnimationLazy, mUnfoldLightRevealOverlayAnimationLazy,
mUnfoldWallpaperController, mUnfoldWallpaperController,
mMoveFromCenterAnimationLazy, mNaturalRotationProgressProvider,
mWallpaperController, mWallpaperController,
mOngoingCallController, mOngoingCallController,
mAnimationScheduler, mAnimationScheduler,

View File

@@ -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
}