Merge "Implement dream out overlay transition" into tm-qpr-dev
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index aa45c20..6e8198b 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -49,6 +49,17 @@
mShowComplications = shouldShowComplications;
onStartDream(layoutParams);
}
+
+ @Override
+ public void wakeUp() {
+ onWakeUp(() -> {
+ try {
+ mDreamOverlayCallback.onWakeUpComplete();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not notify dream of wakeUp:" + e);
+ }
+ });
+ }
};
IDreamOverlayCallback mDreamOverlayCallback;
@@ -71,6 +82,17 @@
public abstract void onStartDream(@NonNull WindowManager.LayoutParams layoutParams);
/**
+ * This method is overridden by implementations to handle when the dream has been requested
+ * to wakeup. This allows any overlay animations to run.
+ *
+ * @param onCompleteCallback The callback to trigger to notify the dream service that the
+ * overlay has completed waking up.
+ * @hide
+ */
+ public void onWakeUp(@NonNull Runnable onCompleteCallback) {
+ }
+
+ /**
* This method is invoked to request the dream exit.
*/
public final void requestExit() {
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index bb22920..8b9852a 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -312,7 +312,14 @@
@Override
public void onExitRequested() {
// Simply finish dream when exit is requested.
- finish();
+ mHandler.post(() -> finish());
+ }
+
+ @Override
+ public void onWakeUpComplete() {
+ // Finish the dream once overlay animations are complete. Execute on handler since
+ // this is coming in on the overlay binder.
+ mHandler.post(() -> finish());
}
};
@@ -975,7 +982,18 @@
* </p>
*/
public void onWakeUp() {
- finish();
+ if (mOverlayConnection != null) {
+ mOverlayConnection.addConsumer(overlay -> {
+ try {
+ overlay.wakeUp();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error waking the overlay service", e);
+ finish();
+ }
+ });
+ } else {
+ finish();
+ }
}
/** {@inheritDoc} */
diff --git a/core/java/android/service/dreams/IDreamOverlay.aidl b/core/java/android/service/dreams/IDreamOverlay.aidl
index 05ebbfe..7aeceb2c 100644
--- a/core/java/android/service/dreams/IDreamOverlay.aidl
+++ b/core/java/android/service/dreams/IDreamOverlay.aidl
@@ -38,4 +38,7 @@
*/
void startDream(in LayoutParams params, in IDreamOverlayCallback callback,
in String dreamComponent, in boolean shouldShowComplications);
+
+ /** Called when the dream is waking, to do any exit animations */
+ void wakeUp();
}
diff --git a/core/java/android/service/dreams/IDreamOverlayCallback.aidl b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
index ec76a33..4ad63f1 100644
--- a/core/java/android/service/dreams/IDreamOverlayCallback.aidl
+++ b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
@@ -28,4 +28,7 @@
* Invoked to request the dream exit.
*/
void onExitRequested();
+
+ /** Invoked when the dream overlay wakeUp animation is complete. */
+ void onWakeUpComplete();
}
\ No newline at end of file
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2a9e60a..b9bcf55 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2485,7 +2485,7 @@
<!-- The duration in milliseconds of the dream opening animation. -->
<integer name="config_dreamOpenAnimationDuration">250</integer>
<!-- The duration in milliseconds of the dream closing animation. -->
- <integer name="config_dreamCloseAnimationDuration">100</integer>
+ <integer name="config_dreamCloseAnimationDuration">300</integer>
<!-- Whether to dismiss the active dream when an activity is started. Doesn't apply to
assistant activities (ACTIVITY_TYPE_ASSISTANT) -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 55d6379..f4d802b 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -743,12 +743,35 @@
<!-- How long in milliseconds before full burn-in protection is achieved. -->
<integer name="config_dreamOverlayMillisUntilFullJitter">240000</integer>
+ <!-- The duration in milliseconds of the y-translation animation when waking up from
+ the dream -->
+ <integer name="config_dreamOverlayOutTranslationYDurationMs">333</integer>
+ <!-- The delay in milliseconds of the y-translation animation when waking up from
+ the dream for the complications at the bottom of the screen -->
+ <integer name="config_dreamOverlayOutTranslationYDelayBottomMs">33</integer>
+ <!-- The delay in milliseconds of the y-translation animation when waking up from
+ the dream for the complications at the top of the screen -->
+ <integer name="config_dreamOverlayOutTranslationYDelayTopMs">117</integer>
+ <!-- The duration in milliseconds of the alpha animation when waking up from the dream -->
+ <integer name="config_dreamOverlayOutAlphaDurationMs">200</integer>
+ <!-- The delay in milliseconds of the alpha animation when waking up from the dream for the
+ complications at the top of the screen -->
+ <integer name="config_dreamOverlayOutAlphaDelayTopMs">217</integer>
+ <!-- The delay in milliseconds of the alpha animation when waking up from the dream for the
+ complications at the bottom of the screen -->
+ <integer name="config_dreamOverlayOutAlphaDelayBottomMs">133</integer>
+ <!-- The duration in milliseconds of the blur animation when waking up from
+ the dream -->
+ <integer name="config_dreamOverlayOutBlurDurationMs">250</integer>
+
<integer name="complicationFadeOutMs">500</integer>
<integer name="complicationFadeInMs">500</integer>
<integer name="complicationRestoreMs">1000</integer>
+ <integer name="complicationFadeOutDelayMs">200</integer>
+
<!-- Duration in milliseconds of the dream in un-blur animation. -->
<integer name="config_dreamOverlayInBlurDurationMs">249</integer>
<!-- Delay in milliseconds of the dream in un-blur animation. -->
@@ -780,27 +803,6 @@
<item>com.android.systemui</item>
</string-array>
- <!-- The thresholds which determine the color used by the AQI dream overlay.
- NOTE: This must always be kept sorted from low to high -->
- <integer-array name="config_dreamAqiThresholds">
- <item>-1</item>
- <item>50</item>
- <item>100</item>
- <item>150</item>
- <item>200</item>
- <item>300</item>
- </integer-array>
-
- <!-- The color values which correspond to the thresholds above -->
- <integer-array name="config_dreamAqiColorValues">
- <item>@color/dream_overlay_aqi_good</item>
- <item>@color/dream_overlay_aqi_moderate</item>
- <item>@color/dream_overlay_aqi_unhealthy_sensitive</item>
- <item>@color/dream_overlay_aqi_unhealthy</item>
- <item>@color/dream_overlay_aqi_very_unhealthy</item>
- <item>@color/dream_overlay_aqi_hazardous</item>
- </integer-array>
-
<!-- Whether the device should display hotspot UI. If true, UI will display only when tethering
is available. If false, UI will never show regardless of tethering availability" -->
<bool name="config_show_wifi_tethering">true</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c78d36d..7cda9d7 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1534,6 +1534,7 @@
<dimen name="dream_overlay_complication_margin">0dp</dimen>
<dimen name="dream_overlay_y_offset">80dp</dimen>
+ <dimen name="dream_overlay_exit_y_offset">40dp</dimen>
<dimen name="dream_aqi_badge_corner_radius">28dp</dimen>
<dimen name="dream_aqi_badge_padding_vertical">6dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index d8dd6a2..0087c84 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -17,17 +17,19 @@
package com.android.systemui.dreams
import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.view.View
+import android.view.animation.Interpolator
+import androidx.annotation.FloatRange
import androidx.core.animation.doOnEnd
import com.android.systemui.animation.Interpolators
import com.android.systemui.dreams.complication.ComplicationHostViewController
import com.android.systemui.dreams.complication.ComplicationLayoutParams
+import com.android.systemui.dreams.complication.ComplicationLayoutParams.Position
import com.android.systemui.dreams.dagger.DreamOverlayModule
import com.android.systemui.statusbar.BlurUtils
-import java.util.function.Consumer
+import com.android.systemui.statusbar.CrossFadeHelper
import javax.inject.Inject
import javax.inject.Named
@@ -40,108 +42,239 @@
private val mStatusBarViewController: DreamOverlayStatusBarViewController,
private val mOverlayStateController: DreamOverlayStateController,
@Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DURATION)
- private val mDreamInBlurAnimDuration: Int,
- @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DELAY) private val mDreamInBlurAnimDelay: Int,
+ private val mDreamInBlurAnimDurationMs: Long,
+ @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DELAY)
+ private val mDreamInBlurAnimDelayMs: Long,
@Named(DreamOverlayModule.DREAM_IN_COMPLICATIONS_ANIMATION_DURATION)
- private val mDreamInComplicationsAnimDuration: Int,
+ private val mDreamInComplicationsAnimDurationMs: Long,
@Named(DreamOverlayModule.DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY)
- private val mDreamInTopComplicationsAnimDelay: Int,
+ private val mDreamInTopComplicationsAnimDelayMs: Long,
@Named(DreamOverlayModule.DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY)
- private val mDreamInBottomComplicationsAnimDelay: Int
+ private val mDreamInBottomComplicationsAnimDelayMs: Long,
+ @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DISTANCE)
+ private val mDreamOutTranslationYDistance: Int,
+ @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DURATION)
+ private val mDreamOutTranslationYDurationMs: Long,
+ @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM)
+ private val mDreamOutTranslationYDelayBottomMs: Long,
+ @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DELAY_TOP)
+ private val mDreamOutTranslationYDelayTopMs: Long,
+ @Named(DreamOverlayModule.DREAM_OUT_ALPHA_DURATION) private val mDreamOutAlphaDurationMs: Long,
+ @Named(DreamOverlayModule.DREAM_OUT_ALPHA_DELAY_BOTTOM)
+ private val mDreamOutAlphaDelayBottomMs: Long,
+ @Named(DreamOverlayModule.DREAM_OUT_ALPHA_DELAY_TOP) private val mDreamOutAlphaDelayTopMs: Long,
+ @Named(DreamOverlayModule.DREAM_OUT_BLUR_DURATION) private val mDreamOutBlurDurationMs: Long
) {
- var mEntryAnimations: AnimatorSet? = null
+ private var mAnimator: Animator? = null
+
+ /**
+ * Store the current alphas at the various positions. This is so that we may resume an animation
+ * at the current alpha.
+ */
+ private var mCurrentAlphaAtPosition = mutableMapOf<Int, Float>()
+
+ @FloatRange(from = 0.0, to = 1.0) private var mBlurProgress: Float = 0f
/** Starts the dream content and dream overlay entry animations. */
- fun startEntryAnimations(view: View) {
- cancelRunningEntryAnimations()
+ @JvmOverloads
+ fun startEntryAnimations(view: View, animatorBuilder: () -> AnimatorSet = { AnimatorSet() }) {
+ cancelAnimations()
- mEntryAnimations = AnimatorSet()
- mEntryAnimations?.apply {
- playTogether(
- buildDreamInBlurAnimator(view),
- buildDreamInTopComplicationsAnimator(),
- buildDreamInBottomComplicationsAnimator()
- )
- doOnEnd { mOverlayStateController.setEntryAnimationsFinished(true) }
- start()
- }
+ mAnimator =
+ animatorBuilder().apply {
+ playTogether(
+ blurAnimator(
+ view = view,
+ from = 1f,
+ to = 0f,
+ durationMs = mDreamInBlurAnimDurationMs,
+ delayMs = mDreamInBlurAnimDelayMs
+ ),
+ alphaAnimator(
+ from = 0f,
+ to = 1f,
+ durationMs = mDreamInComplicationsAnimDurationMs,
+ delayMs = mDreamInTopComplicationsAnimDelayMs,
+ position = ComplicationLayoutParams.POSITION_TOP
+ ),
+ alphaAnimator(
+ from = 0f,
+ to = 1f,
+ durationMs = mDreamInComplicationsAnimDurationMs,
+ delayMs = mDreamInBottomComplicationsAnimDelayMs,
+ position = ComplicationLayoutParams.POSITION_BOTTOM
+ )
+ )
+ doOnEnd {
+ mAnimator = null
+ mOverlayStateController.setEntryAnimationsFinished(true)
+ }
+ start()
+ }
+ }
+
+ /** Starts the dream content and dream overlay exit animations. */
+ @JvmOverloads
+ fun startExitAnimations(
+ view: View,
+ doneCallback: () -> Unit,
+ animatorBuilder: () -> AnimatorSet = { AnimatorSet() }
+ ) {
+ cancelAnimations()
+
+ mAnimator =
+ animatorBuilder().apply {
+ playTogether(
+ blurAnimator(
+ view = view,
+ // Start the blurring wherever the entry animation ended, in
+ // case it was cancelled early.
+ from = mBlurProgress,
+ to = 1f,
+ durationMs = mDreamOutBlurDurationMs
+ ),
+ translationYAnimator(
+ from = 0f,
+ to = mDreamOutTranslationYDistance.toFloat(),
+ durationMs = mDreamOutTranslationYDurationMs,
+ delayMs = mDreamOutTranslationYDelayBottomMs,
+ position = ComplicationLayoutParams.POSITION_BOTTOM,
+ animInterpolator = Interpolators.EMPHASIZED_ACCELERATE
+ ),
+ translationYAnimator(
+ from = 0f,
+ to = mDreamOutTranslationYDistance.toFloat(),
+ durationMs = mDreamOutTranslationYDurationMs,
+ delayMs = mDreamOutTranslationYDelayTopMs,
+ position = ComplicationLayoutParams.POSITION_TOP,
+ animInterpolator = Interpolators.EMPHASIZED_ACCELERATE
+ ),
+ alphaAnimator(
+ from =
+ mCurrentAlphaAtPosition.getOrDefault(
+ key = ComplicationLayoutParams.POSITION_BOTTOM,
+ defaultValue = 1f
+ ),
+ to = 0f,
+ durationMs = mDreamOutAlphaDurationMs,
+ delayMs = mDreamOutAlphaDelayBottomMs,
+ position = ComplicationLayoutParams.POSITION_BOTTOM
+ ),
+ alphaAnimator(
+ from =
+ mCurrentAlphaAtPosition.getOrDefault(
+ key = ComplicationLayoutParams.POSITION_TOP,
+ defaultValue = 1f
+ ),
+ to = 0f,
+ durationMs = mDreamOutAlphaDurationMs,
+ delayMs = mDreamOutAlphaDelayTopMs,
+ position = ComplicationLayoutParams.POSITION_TOP
+ )
+ )
+ doOnEnd {
+ mAnimator = null
+ mOverlayStateController.setExitAnimationsRunning(false)
+ doneCallback()
+ }
+ start()
+ }
+ mOverlayStateController.setExitAnimationsRunning(true)
}
/** Cancels the dream content and dream overlay animations, if they're currently running. */
- fun cancelRunningEntryAnimations() {
- if (mEntryAnimations?.isRunning == true) {
- mEntryAnimations?.cancel()
- }
- mEntryAnimations = null
+ fun cancelAnimations() {
+ mAnimator =
+ mAnimator?.let {
+ it.cancel()
+ null
+ }
}
- private fun buildDreamInBlurAnimator(view: View): Animator {
- return ValueAnimator.ofFloat(1f, 0f).apply {
- duration = mDreamInBlurAnimDuration.toLong()
- startDelay = mDreamInBlurAnimDelay.toLong()
+ private fun blurAnimator(
+ view: View,
+ from: Float,
+ to: Float,
+ durationMs: Long,
+ delayMs: Long = 0
+ ): Animator {
+ return ValueAnimator.ofFloat(from, to).apply {
+ duration = durationMs
+ startDelay = delayMs
interpolator = Interpolators.LINEAR
addUpdateListener { animator: ValueAnimator ->
+ mBlurProgress = animator.animatedValue as Float
mBlurUtils.applyBlur(
- view.viewRootImpl,
- mBlurUtils.blurRadiusOfRatio(animator.animatedValue as Float).toInt(),
- false /*opaque*/
+ viewRootImpl = view.viewRootImpl,
+ radius = mBlurUtils.blurRadiusOfRatio(mBlurProgress).toInt(),
+ opaque = false
)
}
}
}
- private fun buildDreamInTopComplicationsAnimator(): Animator {
- return ValueAnimator.ofFloat(0f, 1f).apply {
- duration = mDreamInComplicationsAnimDuration.toLong()
- startDelay = mDreamInTopComplicationsAnimDelay.toLong()
+ private fun alphaAnimator(
+ from: Float,
+ to: Float,
+ durationMs: Long,
+ delayMs: Long,
+ @Position position: Int
+ ): Animator {
+ return ValueAnimator.ofFloat(from, to).apply {
+ duration = durationMs
+ startDelay = delayMs
interpolator = Interpolators.LINEAR
addUpdateListener { va: ValueAnimator ->
- setTopElementsAlpha(va.animatedValue as Float)
+ setElementsAlphaAtPosition(
+ alpha = va.animatedValue as Float,
+ position = position,
+ fadingOut = to < from
+ )
}
}
}
- private fun buildDreamInBottomComplicationsAnimator(): Animator {
- return ValueAnimator.ofFloat(0f, 1f).apply {
- duration = mDreamInComplicationsAnimDuration.toLong()
- startDelay = mDreamInBottomComplicationsAnimDelay.toLong()
- interpolator = Interpolators.LINEAR
+ private fun translationYAnimator(
+ from: Float,
+ to: Float,
+ durationMs: Long,
+ delayMs: Long,
+ @Position position: Int,
+ animInterpolator: Interpolator
+ ): Animator {
+ return ValueAnimator.ofFloat(from, to).apply {
+ duration = durationMs
+ startDelay = delayMs
+ interpolator = animInterpolator
addUpdateListener { va: ValueAnimator ->
- setBottomElementsAlpha(va.animatedValue as Float)
+ setElementsTranslationYAtPosition(va.animatedValue as Float, position)
}
- addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator) {
- mComplicationHostViewController
- .getViewsAtPosition(ComplicationLayoutParams.POSITION_BOTTOM)
- .forEach(Consumer { v: View -> v.visibility = View.VISIBLE })
- }
- }
- )
}
}
- /** Sets alpha of top complications and the status bar. */
- private fun setTopElementsAlpha(alpha: Float) {
- mComplicationHostViewController
- .getViewsAtPosition(ComplicationLayoutParams.POSITION_TOP)
- .forEach(Consumer { v: View -> setAlphaAndEnsureVisible(v, alpha) })
- mStatusBarViewController.setAlpha(alpha)
- }
-
- /** Sets alpha of bottom complications. */
- private fun setBottomElementsAlpha(alpha: Float) {
- mComplicationHostViewController
- .getViewsAtPosition(ComplicationLayoutParams.POSITION_BOTTOM)
- .forEach(Consumer { v: View -> setAlphaAndEnsureVisible(v, alpha) })
- }
-
- private fun setAlphaAndEnsureVisible(view: View, alpha: Float) {
- if (alpha > 0 && view.visibility != View.VISIBLE) {
- view.visibility = View.VISIBLE
+ /** Sets alpha of complications at the specified position. */
+ private fun setElementsAlphaAtPosition(alpha: Float, position: Int, fadingOut: Boolean) {
+ mCurrentAlphaAtPosition[position] = alpha
+ mComplicationHostViewController.getViewsAtPosition(position).forEach { view ->
+ if (fadingOut) {
+ CrossFadeHelper.fadeOut(view, 1 - alpha, /* remap= */ false)
+ } else {
+ CrossFadeHelper.fadeIn(view, alpha, /* remap= */ false)
+ }
}
+ if (position == ComplicationLayoutParams.POSITION_TOP) {
+ mStatusBarViewController.setFadeAmount(alpha, fadingOut)
+ }
+ }
- view.alpha = alpha
+ /** Sets y translation of complications at the specified position. */
+ private fun setElementsTranslationYAtPosition(translationY: Float, position: Int) {
+ mComplicationHostViewController.getViewsAtPosition(position).forEach { v ->
+ v.translationY = translationY
+ }
+ if (position == ComplicationLayoutParams.POSITION_TOP) {
+ mStatusBarViewController.setTranslationY(translationY)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 5c6d248..9d7ad30 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -29,6 +29,8 @@
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
@@ -42,6 +44,7 @@
import com.android.systemui.util.ViewController;
import java.util.Arrays;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
@@ -194,7 +197,7 @@
}
mPrimaryBouncerCallbackInteractor.removeBouncerExpansionCallback(mBouncerExpansionCallback);
- mDreamOverlayAnimationsController.cancelRunningEntryAnimations();
+ mDreamOverlayAnimationsController.cancelAnimations();
}
View getContainerView() {
@@ -251,4 +254,17 @@
: aboutToShowBouncerProgress(expansion + 0.03f));
return MathUtils.lerp(-mDreamOverlayMaxTranslationY, 0, fraction);
}
+
+ /**
+ * Handle the dream waking up and run any necessary animations.
+ *
+ * @param onAnimationEnd Callback to trigger once animations are finished.
+ * @param callbackExecutor Executor to execute the callback on.
+ */
+ public void wakeUp(@NonNull Runnable onAnimationEnd, @NonNull Executor callbackExecutor) {
+ mDreamOverlayAnimationsController.startExitAnimations(mView, () -> {
+ callbackExecutor.execute(onAnimationEnd);
+ return null;
+ });
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 8542412..e76d5b3 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -213,6 +213,15 @@
mLifecycleRegistry.setCurrentState(state);
}
+ @Override
+ public void onWakeUp(@NonNull Runnable onCompletedCallback) {
+ mExecutor.execute(() -> {
+ if (mDreamOverlayContainerViewController != null) {
+ mDreamOverlayContainerViewController.wakeUp(onCompletedCallback, mExecutor);
+ }
+ });
+ }
+
/**
* Inserts {@link Window} to host the dream overlay into the dream's parent window. Must be
* called from the main executing thread. The window attributes closely mirror those that are
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index e80d0be..5f942b6 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -52,6 +52,7 @@
public static final int STATE_DREAM_OVERLAY_ACTIVE = 1 << 0;
public static final int STATE_LOW_LIGHT_ACTIVE = 1 << 1;
public static final int STATE_DREAM_ENTRY_ANIMATIONS_FINISHED = 1 << 2;
+ public static final int STATE_DREAM_EXIT_ANIMATIONS_RUNNING = 1 << 3;
private static final int OP_CLEAR_STATE = 1;
private static final int OP_SET_STATE = 2;
@@ -211,6 +212,14 @@
return containsState(STATE_DREAM_ENTRY_ANIMATIONS_FINISHED);
}
+ /**
+ * Returns whether the dream content and dream overlay exit animations are running.
+ * @return {@code true} if animations are running, {@code false} otherwise.
+ */
+ public boolean areExitAnimationsRunning() {
+ return containsState(STATE_DREAM_EXIT_ANIMATIONS_RUNNING);
+ }
+
private boolean containsState(int state) {
return (mState & state) != 0;
}
@@ -257,6 +266,15 @@
}
/**
+ * Sets whether dream content and dream overlay exit animations are running.
+ * @param running {@code true} if exit animations are running, {@code false} otherwise.
+ */
+ public void setExitAnimationsRunning(boolean running) {
+ modifyState(running ? OP_SET_STATE : OP_CLEAR_STATE,
+ STATE_DREAM_EXIT_ANIMATIONS_RUNNING);
+ }
+
+ /**
* Returns the available complication types.
*/
@Complication.ComplicationType
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index d17fbe3..f1bb156 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -37,6 +37,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider.StatusBarItem;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
+import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -217,18 +218,29 @@
}
/**
- * Sets alpha of the dream overlay status bar.
+ * Sets fade of the dream overlay status bar.
*
* No-op if the dream overlay status bar should not be shown.
*/
- protected void setAlpha(float alpha) {
+ protected void setFadeAmount(float fadeAmount, boolean fadingOut) {
updateVisibility();
if (mView.getVisibility() != View.VISIBLE) {
return;
}
- mView.setAlpha(alpha);
+ if (fadingOut) {
+ CrossFadeHelper.fadeOut(mView, 1 - fadeAmount, /* remap= */ false);
+ } else {
+ CrossFadeHelper.fadeIn(mView, fadeAmount, /* remap= */ false);
+ }
+ }
+
+ /**
+ * Sets the y translation of the dream overlay status bar.
+ */
+ public void setTranslationY(float translationY) {
+ mView.setTranslationY(translationY);
}
private boolean shouldShowStatusBar() {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java
index 41f5578..b07efdf 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java
@@ -197,11 +197,11 @@
*/
interface VisibilityController {
/**
- * Called to set the visibility of all shown and future complications.
+ * Called to set the visibility of all shown and future complications. Changes in visibility
+ * will always be animated.
* @param visibility The desired future visibility.
- * @param animate whether the change should be animated.
*/
- void setVisibility(@View.Visibility int visibility, boolean animate);
+ void setVisibility(@View.Visibility int visibility);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
index 440dcbc..48159ae 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
@@ -21,12 +21,9 @@
import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_DEFAULT;
import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Constraints;
@@ -34,6 +31,7 @@
import com.android.systemui.R;
import com.android.systemui.dreams.complication.ComplicationLayoutParams.Position;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
+import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.touch.TouchInsetManager;
import java.util.ArrayList;
@@ -481,7 +479,6 @@
private final TouchInsetManager.TouchInsetSession mSession;
private final int mFadeInDuration;
private final int mFadeOutDuration;
- private ViewPropertyAnimator mViewPropertyAnimator;
/** */
@Inject
@@ -498,26 +495,16 @@
}
@Override
- public void setVisibility(int visibility, boolean animate) {
- final boolean appearing = visibility == View.VISIBLE;
-
- if (mViewPropertyAnimator != null) {
- mViewPropertyAnimator.cancel();
+ public void setVisibility(int visibility) {
+ if (visibility == View.VISIBLE) {
+ CrossFadeHelper.fadeIn(mLayout, mFadeInDuration, /* delay= */ 0);
+ } else {
+ CrossFadeHelper.fadeOut(
+ mLayout,
+ mFadeOutDuration,
+ /* delay= */ 0,
+ /* endRunnable= */ null);
}
-
- if (appearing) {
- mLayout.setVisibility(View.VISIBLE);
- }
-
- mViewPropertyAnimator = mLayout.animate()
- .alpha(appearing ? 1f : 0f)
- .setDuration(appearing ? mFadeInDuration : mFadeOutDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mLayout.setVisibility(visibility);
- }
- });
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java
index 2b32d34..4fae68d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java
@@ -38,7 +38,7 @@
POSITION_START,
})
- @interface Position {}
+ public @interface Position {}
/** Align view with the top of parent or bottom of preceding {@link Complication}. */
public static final int POSITION_TOP = 1 << 0;
/** Align view with the bottom of parent or top of preceding {@link Complication}. */
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java
index c9fecc9..09cc7c5 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java
@@ -41,6 +41,7 @@
public static final String COMPLICATIONS_FADE_OUT_DURATION = "complications_fade_out_duration";
public static final String COMPLICATIONS_FADE_IN_DURATION = "complications_fade_in_duration";
public static final String COMPLICATIONS_RESTORE_TIMEOUT = "complication_restore_timeout";
+ public static final String COMPLICATIONS_FADE_OUT_DELAY = "complication_fade_out_delay";
/**
* Generates a {@link ConstraintLayout}, which can host
@@ -75,6 +76,16 @@
}
/**
+ * Provides the delay to wait for before fading out complications.
+ */
+ @Provides
+ @Named(COMPLICATIONS_FADE_OUT_DELAY)
+ @DreamOverlayComponent.DreamOverlayScope
+ static int providesComplicationsFadeOutDelay(@Main Resources resources) {
+ return resources.getInteger(R.integer.complicationFadeOutDelayMs);
+ }
+
+ /**
* Provides the fade in duration for complications.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index cb012fa..ed0e1d9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -55,6 +55,22 @@
"dream_in_top_complications_anim_delay";
public static final String DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY =
"dream_in_bottom_complications_anim_delay";
+ public static final String DREAM_OUT_TRANSLATION_Y_DISTANCE =
+ "dream_out_complications_translation_y";
+ public static final String DREAM_OUT_TRANSLATION_Y_DURATION =
+ "dream_out_complications_translation_y_duration";
+ public static final String DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM =
+ "dream_out_complications_translation_y_delay_bottom";
+ public static final String DREAM_OUT_TRANSLATION_Y_DELAY_TOP =
+ "dream_out_complications_translation_y_delay_top";
+ public static final String DREAM_OUT_ALPHA_DURATION =
+ "dream_out_complications_alpha_duration";
+ public static final String DREAM_OUT_ALPHA_DELAY_BOTTOM =
+ "dream_out_complications_alpha_delay_bottom";
+ public static final String DREAM_OUT_ALPHA_DELAY_TOP =
+ "dream_out_complications_alpha_delay_top";
+ public static final String DREAM_OUT_BLUR_DURATION =
+ "dream_out_blur_duration";
/** */
@Provides
@@ -127,8 +143,8 @@
*/
@Provides
@Named(DREAM_IN_BLUR_ANIMATION_DURATION)
- static int providesDreamInBlurAnimationDuration(@Main Resources resources) {
- return resources.getInteger(R.integer.config_dreamOverlayInBlurDurationMs);
+ static long providesDreamInBlurAnimationDuration(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayInBlurDurationMs);
}
/**
@@ -136,8 +152,8 @@
*/
@Provides
@Named(DREAM_IN_BLUR_ANIMATION_DELAY)
- static int providesDreamInBlurAnimationDelay(@Main Resources resources) {
- return resources.getInteger(R.integer.config_dreamOverlayInBlurDelayMs);
+ static long providesDreamInBlurAnimationDelay(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayInBlurDelayMs);
}
/**
@@ -145,8 +161,8 @@
*/
@Provides
@Named(DREAM_IN_COMPLICATIONS_ANIMATION_DURATION)
- static int providesDreamInComplicationsAnimationDuration(@Main Resources resources) {
- return resources.getInteger(R.integer.config_dreamOverlayInComplicationsDurationMs);
+ static long providesDreamInComplicationsAnimationDuration(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayInComplicationsDurationMs);
}
/**
@@ -154,8 +170,8 @@
*/
@Provides
@Named(DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY)
- static int providesDreamInTopComplicationsAnimationDelay(@Main Resources resources) {
- return resources.getInteger(R.integer.config_dreamOverlayInTopComplicationsDelayMs);
+ static long providesDreamInTopComplicationsAnimationDelay(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayInTopComplicationsDelayMs);
}
/**
@@ -163,8 +179,69 @@
*/
@Provides
@Named(DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY)
- static int providesDreamInBottomComplicationsAnimationDelay(@Main Resources resources) {
- return resources.getInteger(R.integer.config_dreamOverlayInBottomComplicationsDelayMs);
+ static long providesDreamInBottomComplicationsAnimationDelay(@Main Resources resources) {
+ return (long) resources.getInteger(
+ R.integer.config_dreamOverlayInBottomComplicationsDelayMs);
+ }
+
+ /**
+ * Provides the number of pixels to translate complications when waking up from dream.
+ */
+ @Provides
+ @Named(DREAM_OUT_TRANSLATION_Y_DISTANCE)
+ @DreamOverlayComponent.DreamOverlayScope
+ static int providesDreamOutComplicationsTranslationY(@Main Resources resources) {
+ return resources.getDimensionPixelSize(R.dimen.dream_overlay_exit_y_offset);
+ }
+
+ @Provides
+ @Named(DREAM_OUT_TRANSLATION_Y_DURATION)
+ @DreamOverlayComponent.DreamOverlayScope
+ static long providesDreamOutComplicationsTranslationYDuration(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayOutTranslationYDurationMs);
+ }
+
+ @Provides
+ @Named(DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM)
+ @DreamOverlayComponent.DreamOverlayScope
+ static long providesDreamOutComplicationsTranslationYDelayBottom(@Main Resources resources) {
+ return (long) resources.getInteger(
+ R.integer.config_dreamOverlayOutTranslationYDelayBottomMs);
+ }
+
+ @Provides
+ @Named(DREAM_OUT_TRANSLATION_Y_DELAY_TOP)
+ @DreamOverlayComponent.DreamOverlayScope
+ static long providesDreamOutComplicationsTranslationYDelayTop(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayOutTranslationYDelayTopMs);
+ }
+
+ @Provides
+ @Named(DREAM_OUT_ALPHA_DURATION)
+ @DreamOverlayComponent.DreamOverlayScope
+ static long providesDreamOutComplicationsAlphaDuration(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayOutAlphaDurationMs);
+ }
+
+ @Provides
+ @Named(DREAM_OUT_ALPHA_DELAY_BOTTOM)
+ @DreamOverlayComponent.DreamOverlayScope
+ static long providesDreamOutComplicationsAlphaDelayBottom(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayOutAlphaDelayBottomMs);
+ }
+
+ @Provides
+ @Named(DREAM_OUT_ALPHA_DELAY_TOP)
+ @DreamOverlayComponent.DreamOverlayScope
+ static long providesDreamOutComplicationsAlphaDelayTop(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayOutAlphaDelayTopMs);
+ }
+
+ @Provides
+ @Named(DREAM_OUT_BLUR_DURATION)
+ @DreamOverlayComponent.DreamOverlayScope
+ static long providesDreamOutBlurDuration(@Main Resources resources) {
+ return (long) resources.getInteger(R.integer.config_dreamOverlayOutBlurDurationMs);
}
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
index 3087cdf..e276e0c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
@@ -16,22 +16,26 @@
package com.android.systemui.dreams.touch;
+import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_OUT_DELAY;
import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_RESTORE_TIMEOUT;
-import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import androidx.annotation.Nullable;
+
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.touch.TouchInsetManager;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.google.common.util.concurrent.ListenableFuture;
+import java.util.ArrayDeque;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
@@ -49,33 +53,58 @@
private static final String TAG = "HideComplicationHandler";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final Complication.VisibilityController mVisibilityController;
private final int mRestoreTimeout;
+ private final int mFadeOutDelay;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private final Handler mHandler;
- private final Executor mExecutor;
+ private final DelayableExecutor mExecutor;
+ private final DreamOverlayStateController mOverlayStateController;
private final TouchInsetManager mTouchInsetManager;
+ private final Complication.VisibilityController mVisibilityController;
+ private boolean mHidden = false;
+ @Nullable
+ private Runnable mHiddenCallback;
+ private final ArrayDeque<Runnable> mCancelCallbacks = new ArrayDeque<>();
+
private final Runnable mRestoreComplications = new Runnable() {
@Override
public void run() {
- mVisibilityController.setVisibility(View.VISIBLE, true);
+ mVisibilityController.setVisibility(View.VISIBLE);
+ mHidden = false;
+ }
+ };
+
+ private final Runnable mHideComplications = new Runnable() {
+ @Override
+ public void run() {
+ if (mOverlayStateController.areExitAnimationsRunning()) {
+ // Avoid interfering with the exit animations.
+ return;
+ }
+ mVisibilityController.setVisibility(View.INVISIBLE);
+ mHidden = true;
+ if (mHiddenCallback != null) {
+ mHiddenCallback.run();
+ mHiddenCallback = null;
+ }
}
};
@Inject
HideComplicationTouchHandler(Complication.VisibilityController visibilityController,
@Named(COMPLICATIONS_RESTORE_TIMEOUT) int restoreTimeout,
+ @Named(COMPLICATIONS_FADE_OUT_DELAY) int fadeOutDelay,
TouchInsetManager touchInsetManager,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- @Main Executor executor,
- @Main Handler handler) {
+ @Main DelayableExecutor executor,
+ DreamOverlayStateController overlayStateController) {
mVisibilityController = visibilityController;
mRestoreTimeout = restoreTimeout;
+ mFadeOutDelay = fadeOutDelay;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
- mHandler = handler;
mTouchInsetManager = touchInsetManager;
mExecutor = executor;
+ mOverlayStateController = overlayStateController;
}
@Override
@@ -87,7 +116,8 @@
final boolean bouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
// If other sessions are interested in this touch, do not fade out elements.
- if (session.getActiveSessionCount() > 1 || bouncerShowing) {
+ if (session.getActiveSessionCount() > 1 || bouncerShowing
+ || mOverlayStateController.areExitAnimationsRunning()) {
if (DEBUG) {
Log.d(TAG, "not fading. Active session count: " + session.getActiveSessionCount()
+ ". Bouncer showing: " + bouncerShowing);
@@ -115,8 +145,11 @@
touchCheck.addListener(() -> {
try {
if (!touchCheck.get()) {
- mHandler.removeCallbacks(mRestoreComplications);
- mVisibilityController.setVisibility(View.INVISIBLE, true);
+ // Cancel all pending callbacks.
+ while (!mCancelCallbacks.isEmpty()) mCancelCallbacks.pop().run();
+ mCancelCallbacks.add(
+ mExecutor.executeDelayed(
+ mHideComplications, mFadeOutDelay));
} else {
// If a touch occurred inside the dream overlay touch insets, do not
// handle the touch.
@@ -130,7 +163,23 @@
|| motionEvent.getAction() == MotionEvent.ACTION_UP) {
// End session and initiate delayed reappearance of the complications.
session.pop();
- mHandler.postDelayed(mRestoreComplications, mRestoreTimeout);
+ runAfterHidden(() -> mCancelCallbacks.add(
+ mExecutor.executeDelayed(mRestoreComplications,
+ mRestoreTimeout)));
+ }
+ });
+ }
+
+ /**
+ * Triggers a runnable after complications have been hidden. Will override any previously set
+ * runnable currently waiting for hide to happen.
+ */
+ private void runAfterHidden(Runnable runnable) {
+ mExecutor.execute(() -> {
+ if (mHidden) {
+ runnable.run();
+ } else {
+ mHiddenCallback = runnable;
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 7cd3843..5ed0bff 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -409,6 +409,11 @@
private final int mDreamOpenAnimationDuration;
/**
+ * The duration in milliseconds of the dream close animation.
+ */
+ private final int mDreamCloseAnimationDuration;
+
+ /**
* The animation used for hiding keyguard. This is used to fetch the animation timings if
* WindowManager is not providing us with them.
*/
@@ -1054,7 +1059,8 @@
}
mUnoccludeAnimator = ValueAnimator.ofFloat(1f, 0f);
- mUnoccludeAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
+ mUnoccludeAnimator.setDuration(isDream ? mDreamCloseAnimationDuration
+ : UNOCCLUDE_ANIMATION_DURATION);
mUnoccludeAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE);
mUnoccludeAnimator.addUpdateListener(
animation -> {
@@ -1204,6 +1210,8 @@
mDreamOpenAnimationDuration = context.getResources().getInteger(
com.android.internal.R.integer.config_dreamOpenAnimationDuration);
+ mDreamCloseAnimationDuration = context.getResources().getInteger(
+ com.android.internal.R.integer.config_dreamCloseAnimationDuration);
}
public void userActivity() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
new file mode 100644
index 0000000..99406ed
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -0,0 +1,125 @@
+package com.android.systemui.dreams
+
+import android.animation.Animator
+import android.animation.AnimatorSet
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dreams.complication.ComplicationHostViewController
+import com.android.systemui.statusbar.BlurUtils
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
+
+ companion object {
+ private const val DREAM_IN_BLUR_ANIMATION_DURATION = 1L
+ private const val DREAM_IN_BLUR_ANIMATION_DELAY = 2L
+ private const val DREAM_IN_COMPLICATIONS_ANIMATION_DURATION = 3L
+ private const val DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY = 4L
+ private const val DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY = 5L
+ private const val DREAM_OUT_TRANSLATION_Y_DISTANCE = 6
+ private const val DREAM_OUT_TRANSLATION_Y_DURATION = 7L
+ private const val DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM = 8L
+ private const val DREAM_OUT_TRANSLATION_Y_DELAY_TOP = 9L
+ private const val DREAM_OUT_ALPHA_DURATION = 10L
+ private const val DREAM_OUT_ALPHA_DELAY_BOTTOM = 11L
+ private const val DREAM_OUT_ALPHA_DELAY_TOP = 12L
+ private const val DREAM_OUT_BLUR_DURATION = 13L
+ }
+
+ @Mock private lateinit var mockAnimator: AnimatorSet
+ @Mock private lateinit var blurUtils: BlurUtils
+ @Mock private lateinit var hostViewController: ComplicationHostViewController
+ @Mock private lateinit var statusBarViewController: DreamOverlayStatusBarViewController
+ @Mock private lateinit var stateController: DreamOverlayStateController
+ private lateinit var controller: DreamOverlayAnimationsController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ controller =
+ DreamOverlayAnimationsController(
+ blurUtils,
+ hostViewController,
+ statusBarViewController,
+ stateController,
+ DREAM_IN_BLUR_ANIMATION_DURATION,
+ DREAM_IN_BLUR_ANIMATION_DELAY,
+ DREAM_IN_COMPLICATIONS_ANIMATION_DURATION,
+ DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY,
+ DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY,
+ DREAM_OUT_TRANSLATION_Y_DISTANCE,
+ DREAM_OUT_TRANSLATION_Y_DURATION,
+ DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM,
+ DREAM_OUT_TRANSLATION_Y_DELAY_TOP,
+ DREAM_OUT_ALPHA_DURATION,
+ DREAM_OUT_ALPHA_DELAY_BOTTOM,
+ DREAM_OUT_ALPHA_DELAY_TOP,
+ DREAM_OUT_BLUR_DURATION
+ )
+ }
+
+ @Test
+ fun testExitAnimationOnEnd() {
+ val mockCallback: () -> Unit = mock()
+
+ controller.startExitAnimations(
+ view = mock(),
+ doneCallback = mockCallback,
+ animatorBuilder = { mockAnimator }
+ )
+
+ val captor = argumentCaptor<Animator.AnimatorListener>()
+ verify(mockAnimator).addListener(captor.capture())
+ val listener = captor.value
+
+ verify(mockCallback, never()).invoke()
+ listener.onAnimationEnd(mockAnimator)
+ verify(mockCallback, times(1)).invoke()
+ }
+
+ @Test
+ fun testCancellation() {
+ controller.startExitAnimations(
+ view = mock(),
+ doneCallback = mock(),
+ animatorBuilder = { mockAnimator }
+ )
+
+ verify(mockAnimator, never()).cancel()
+ controller.cancelAnimations()
+ verify(mockAnimator, times(1)).cancel()
+ }
+
+ @Test
+ fun testExitAfterStartWillCancel() {
+ val mockStartAnimator: AnimatorSet = mock()
+ val mockExitAnimator: AnimatorSet = mock()
+
+ controller.startEntryAnimations(view = mock(), animatorBuilder = { mockStartAnimator })
+
+ verify(mockStartAnimator, never()).cancel()
+
+ controller.startExitAnimations(
+ view = mock(),
+ doneCallback = mock(),
+ animatorBuilder = { mockExitAnimator }
+ )
+
+ // Verify that we cancelled the start animator in favor of the exit
+ // animator.
+ verify(mockStartAnimator, times(1)).cancel()
+ verify(mockExitAnimator, never()).cancel()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 517804d..73c226d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -204,7 +204,7 @@
mController.onViewAttached();
verify(mAnimationsController).startEntryAnimations(mDreamOverlayContainerView);
- verify(mAnimationsController, never()).cancelRunningEntryAnimations();
+ verify(mAnimationsController, never()).cancelAnimations();
}
@Test
@@ -221,6 +221,6 @@
mController.onViewAttached();
mController.onViewDetached();
- verify(mAnimationsController).cancelRunningEntryAnimations();
+ verify(mAnimationsController).cancelAnimations();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index f04a37f..ffb8342 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -337,4 +338,28 @@
verify(mDreamOverlayComponent).getDreamOverlayContainerViewController();
verify(mDreamOverlayComponent).getDreamOverlayTouchMonitor();
}
+
+ @Test
+ public void testWakeUp() throws RemoteException {
+ final IBinder proxy = mService.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
+
+ // Inform the overlay service of dream starting.
+ overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+ true /*shouldShowComplication*/);
+ mMainExecutor.runAllReady();
+
+ final Runnable callback = mock(Runnable.class);
+ mService.onWakeUp(callback);
+ mMainExecutor.runAllReady();
+ verify(mDreamOverlayContainerViewController).wakeUp(callback, mMainExecutor);
+ }
+
+ @Test
+ public void testWakeUpBeforeStartDoesNothing() {
+ final Runnable callback = mock(Runnable.class);
+ mService.onWakeUp(callback);
+ mMainExecutor.runAllReady();
+ verify(mDreamOverlayContainerViewController, never()).wakeUp(callback, mMainExecutor);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java
index 14a5702..4e3aca7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.dreams.touch;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@@ -33,6 +31,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -52,6 +51,7 @@
@RunWith(AndroidTestingRunner.class)
public class HideComplicationTouchHandlerTest extends SysuiTestCase {
private static final int RESTORE_TIMEOUT = 1000;
+ private static final int HIDE_DELAY = 500;
@Mock
Complication.VisibilityController mVisibilityController;
@@ -71,11 +71,18 @@
@Mock
DreamTouchHandler.TouchSession mSession;
- FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+ @Mock
+ DreamOverlayStateController mStateController;
+
+ FakeSystemClock mClock;
+
+ FakeExecutor mFakeExecutor;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ mClock = new FakeSystemClock();
+ mFakeExecutor = new FakeExecutor(mClock);
}
/**
@@ -86,10 +93,11 @@
final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(
mVisibilityController,
RESTORE_TIMEOUT,
+ HIDE_DELAY,
mTouchInsetManager,
mStatusBarKeyguardViewManager,
mFakeExecutor,
- mHandler);
+ mStateController);
// Report multiple active sessions.
when(mSession.getActiveSessionCount()).thenReturn(2);
@@ -103,8 +111,10 @@
// Verify session end.
verify(mSession).pop();
+ mClock.advanceTime(HIDE_DELAY);
+
// Verify no interaction with visibility controller.
- verify(mVisibilityController, never()).setVisibility(anyInt(), anyBoolean());
+ verify(mVisibilityController, never()).setVisibility(anyInt());
}
/**
@@ -115,10 +125,11 @@
final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(
mVisibilityController,
RESTORE_TIMEOUT,
+ HIDE_DELAY,
mTouchInsetManager,
mStatusBarKeyguardViewManager,
mFakeExecutor,
- mHandler);
+ mStateController);
// Report one session.
when(mSession.getActiveSessionCount()).thenReturn(1);
@@ -132,8 +143,10 @@
// Verify session end.
verify(mSession).pop();
+ mClock.advanceTime(HIDE_DELAY);
+
// Verify no interaction with visibility controller.
- verify(mVisibilityController, never()).setVisibility(anyInt(), anyBoolean());
+ verify(mVisibilityController, never()).setVisibility(anyInt());
}
/**
@@ -144,10 +157,11 @@
final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(
mVisibilityController,
RESTORE_TIMEOUT,
+ HIDE_DELAY,
mTouchInsetManager,
mStatusBarKeyguardViewManager,
mFakeExecutor,
- mHandler);
+ mStateController);
// Report one session
when(mSession.getActiveSessionCount()).thenReturn(1);
@@ -177,8 +191,10 @@
// Verify session ended.
verify(mSession).pop();
+ mClock.advanceTime(HIDE_DELAY);
+
// Verify no interaction with visibility controller.
- verify(mVisibilityController, never()).setVisibility(anyInt(), anyBoolean());
+ verify(mVisibilityController, never()).setVisibility(anyInt());
}
/**
@@ -189,10 +205,11 @@
final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(
mVisibilityController,
RESTORE_TIMEOUT,
+ HIDE_DELAY,
mTouchInsetManager,
mStatusBarKeyguardViewManager,
mFakeExecutor,
- mHandler);
+ mStateController);
// Report one session
when(mSession.getActiveSessionCount()).thenReturn(1);
@@ -221,11 +238,11 @@
inputEventListenerCaptor.getValue().onInputEvent(mMotionEvent);
mFakeExecutor.runAllReady();
- // Verify callback to restore visibility cancelled.
- verify(mHandler).removeCallbacks(any());
-
+ // Verify visibility controller doesn't hide until after timeout
+ verify(mVisibilityController, never()).setVisibility(eq(View.INVISIBLE));
+ mClock.advanceTime(HIDE_DELAY);
// Verify visibility controller told to hide complications.
- verify(mVisibilityController).setVisibility(eq(View.INVISIBLE), anyBoolean());
+ verify(mVisibilityController).setVisibility(eq(View.INVISIBLE));
Mockito.clearInvocations(mVisibilityController, mHandler);
@@ -235,11 +252,8 @@
mFakeExecutor.runAllReady();
// Verify visibility controller told to show complications.
- ArgumentCaptor<Runnable> delayRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mHandler).postDelayed(delayRunnableCaptor.capture(),
- eq(Long.valueOf(RESTORE_TIMEOUT)));
- delayRunnableCaptor.getValue().run();
- verify(mVisibilityController).setVisibility(eq(View.VISIBLE), anyBoolean());
+ mClock.advanceTime(RESTORE_TIMEOUT);
+ verify(mVisibilityController).setVisibility(eq(View.VISIBLE));
// Verify session ended.
verify(mSession).pop();