Merge "Dream IN blur + complications fade-in animations." into tm-qpr-dev
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/dream_overlay_status_bar"
|
android:id="@+id/dream_overlay_status_bar"
|
||||||
|
android:visibility="invisible"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/dream_overlay_status_bar_height"
|
android:layout_height="@dimen/dream_overlay_status_bar_height"
|
||||||
android:paddingEnd="@dimen/dream_overlay_status_bar_margin"
|
android:paddingEnd="@dimen/dream_overlay_status_bar_margin"
|
||||||
|
|||||||
@@ -743,6 +743,17 @@
|
|||||||
|
|
||||||
<integer name="complicationRestoreMs">1000</integer>
|
<integer name="complicationRestoreMs">1000</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. -->
|
||||||
|
<integer name="config_dreamOverlayInBlurDelayMs">133</integer>
|
||||||
|
<!-- Duration in milliseconds of the dream in complications fade-in animation. -->
|
||||||
|
<integer name="config_dreamOverlayInComplicationsDurationMs">282</integer>
|
||||||
|
<!-- Delay in milliseconds of the dream in top complications fade-in animation. -->
|
||||||
|
<integer name="config_dreamOverlayInTopComplicationsDelayMs">216</integer>
|
||||||
|
<!-- Delay in milliseconds of the dream in bottom complications fade-in animation. -->
|
||||||
|
<integer name="config_dreamOverlayInBottomComplicationsDelayMs">299</integer>
|
||||||
|
|
||||||
<!-- Icons that don't show in a collapsed non-keyguard statusbar -->
|
<!-- Icons that don't show in a collapsed non-keyguard statusbar -->
|
||||||
<string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false">
|
<string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false">
|
||||||
<item>@*android:string/status_bar_volume</item>
|
<item>@*android:string/status_bar_volume</item>
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.dreams
|
||||||
|
|
||||||
|
import android.animation.Animator
|
||||||
|
import android.animation.AnimatorListenerAdapter
|
||||||
|
import android.animation.AnimatorSet
|
||||||
|
import android.animation.ValueAnimator
|
||||||
|
import android.view.View
|
||||||
|
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.dagger.DreamOverlayModule
|
||||||
|
import com.android.systemui.statusbar.BlurUtils
|
||||||
|
import java.util.function.Consumer
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Named
|
||||||
|
|
||||||
|
/** Controller for dream overlay animations. */
|
||||||
|
class DreamOverlayAnimationsController
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val mBlurUtils: BlurUtils,
|
||||||
|
private val mComplicationHostViewController: ComplicationHostViewController,
|
||||||
|
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,
|
||||||
|
@Named(DreamOverlayModule.DREAM_IN_COMPLICATIONS_ANIMATION_DURATION)
|
||||||
|
private val mDreamInComplicationsAnimDuration: Int,
|
||||||
|
@Named(DreamOverlayModule.DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY)
|
||||||
|
private val mDreamInTopComplicationsAnimDelay: Int,
|
||||||
|
@Named(DreamOverlayModule.DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY)
|
||||||
|
private val mDreamInBottomComplicationsAnimDelay: Int
|
||||||
|
) {
|
||||||
|
|
||||||
|
var mEntryAnimations: AnimatorSet? = null
|
||||||
|
|
||||||
|
/** Starts the dream content and dream overlay entry animations. */
|
||||||
|
fun startEntryAnimations(view: View) {
|
||||||
|
cancelRunningEntryAnimations()
|
||||||
|
|
||||||
|
mEntryAnimations = AnimatorSet()
|
||||||
|
mEntryAnimations?.apply {
|
||||||
|
playTogether(
|
||||||
|
buildDreamInBlurAnimator(view),
|
||||||
|
buildDreamInTopComplicationsAnimator(),
|
||||||
|
buildDreamInBottomComplicationsAnimator()
|
||||||
|
)
|
||||||
|
doOnEnd { mOverlayStateController.setEntryAnimationsFinished(true) }
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cancels the dream content and dream overlay animations, if they're currently running. */
|
||||||
|
fun cancelRunningEntryAnimations() {
|
||||||
|
if (mEntryAnimations?.isRunning == true) {
|
||||||
|
mEntryAnimations?.cancel()
|
||||||
|
}
|
||||||
|
mEntryAnimations = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDreamInBlurAnimator(view: View): Animator {
|
||||||
|
return ValueAnimator.ofFloat(1f, 0f).apply {
|
||||||
|
duration = mDreamInBlurAnimDuration.toLong()
|
||||||
|
startDelay = mDreamInBlurAnimDelay.toLong()
|
||||||
|
interpolator = Interpolators.LINEAR
|
||||||
|
addUpdateListener { animator: ValueAnimator ->
|
||||||
|
mBlurUtils.applyBlur(
|
||||||
|
view.viewRootImpl,
|
||||||
|
mBlurUtils.blurRadiusOfRatio(animator.animatedValue as Float).toInt(),
|
||||||
|
false /*opaque*/
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDreamInTopComplicationsAnimator(): Animator {
|
||||||
|
return ValueAnimator.ofFloat(0f, 1f).apply {
|
||||||
|
duration = mDreamInComplicationsAnimDuration.toLong()
|
||||||
|
startDelay = mDreamInTopComplicationsAnimDelay.toLong()
|
||||||
|
interpolator = Interpolators.LINEAR
|
||||||
|
addUpdateListener { va: ValueAnimator ->
|
||||||
|
setTopElementsAlpha(va.animatedValue as Float)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDreamInBottomComplicationsAnimator(): Animator {
|
||||||
|
return ValueAnimator.ofFloat(0f, 1f).apply {
|
||||||
|
duration = mDreamInComplicationsAnimDuration.toLong()
|
||||||
|
startDelay = mDreamInBottomComplicationsAnimDelay.toLong()
|
||||||
|
interpolator = Interpolators.LINEAR
|
||||||
|
addUpdateListener { va: ValueAnimator ->
|
||||||
|
setBottomElementsAlpha(va.animatedValue as Float)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
view.alpha = alpha
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,6 +54,8 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
|
|||||||
private final DreamOverlayStatusBarViewController mStatusBarViewController;
|
private final DreamOverlayStatusBarViewController mStatusBarViewController;
|
||||||
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
||||||
private final BlurUtils mBlurUtils;
|
private final BlurUtils mBlurUtils;
|
||||||
|
private final DreamOverlayAnimationsController mDreamOverlayAnimationsController;
|
||||||
|
private final DreamOverlayStateController mStateController;
|
||||||
|
|
||||||
private final ComplicationHostViewController mComplicationHostViewController;
|
private final ComplicationHostViewController mComplicationHostViewController;
|
||||||
|
|
||||||
@@ -134,12 +136,16 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
|
|||||||
@Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
|
@Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
|
||||||
burnInProtectionUpdateInterval,
|
burnInProtectionUpdateInterval,
|
||||||
@Named(DreamOverlayModule.MILLIS_UNTIL_FULL_JITTER) long millisUntilFullJitter,
|
@Named(DreamOverlayModule.MILLIS_UNTIL_FULL_JITTER) long millisUntilFullJitter,
|
||||||
BouncerCallbackInteractor bouncerCallbackInteractor) {
|
BouncerCallbackInteractor bouncerCallbackInteractor,
|
||||||
|
DreamOverlayAnimationsController animationsController,
|
||||||
|
DreamOverlayStateController stateController) {
|
||||||
super(containerView);
|
super(containerView);
|
||||||
mDreamOverlayContentView = contentView;
|
mDreamOverlayContentView = contentView;
|
||||||
mStatusBarViewController = statusBarViewController;
|
mStatusBarViewController = statusBarViewController;
|
||||||
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
|
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
|
||||||
mBlurUtils = blurUtils;
|
mBlurUtils = blurUtils;
|
||||||
|
mDreamOverlayAnimationsController = animationsController;
|
||||||
|
mStateController = stateController;
|
||||||
|
|
||||||
mComplicationHostViewController = complicationHostViewController;
|
mComplicationHostViewController = complicationHostViewController;
|
||||||
mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize(
|
mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize(
|
||||||
@@ -172,6 +178,11 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
|
|||||||
bouncer.addBouncerExpansionCallback(mBouncerExpansionCallback);
|
bouncer.addBouncerExpansionCallback(mBouncerExpansionCallback);
|
||||||
}
|
}
|
||||||
mBouncerCallbackInteractor.addBouncerExpansionCallback(mBouncerExpansionCallback);
|
mBouncerCallbackInteractor.addBouncerExpansionCallback(mBouncerExpansionCallback);
|
||||||
|
|
||||||
|
// Start dream entry animations. Skip animations for low light clock.
|
||||||
|
if (!mStateController.isLowLightActive()) {
|
||||||
|
mDreamOverlayAnimationsController.startEntryAnimations(mView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -182,6 +193,8 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
|
|||||||
bouncer.removeBouncerExpansionCallback(mBouncerExpansionCallback);
|
bouncer.removeBouncerExpansionCallback(mBouncerExpansionCallback);
|
||||||
}
|
}
|
||||||
mBouncerCallbackInteractor.removeBouncerExpansionCallback(mBouncerExpansionCallback);
|
mBouncerCallbackInteractor.removeBouncerExpansionCallback(mBouncerExpansionCallback);
|
||||||
|
|
||||||
|
mDreamOverlayAnimationsController.cancelRunningEntryAnimations();
|
||||||
}
|
}
|
||||||
|
|
||||||
View getContainerView() {
|
View getContainerView() {
|
||||||
|
|||||||
@@ -257,6 +257,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
|
|||||||
|
|
||||||
mStateController.setOverlayActive(false);
|
mStateController.setOverlayActive(false);
|
||||||
mStateController.setLowLightActive(false);
|
mStateController.setLowLightActive(false);
|
||||||
|
mStateController.setEntryAnimationsFinished(false);
|
||||||
|
|
||||||
mDreamOverlayContainerViewController = null;
|
mDreamOverlayContainerViewController = null;
|
||||||
mDreamOverlayTouchMonitor = null;
|
mDreamOverlayTouchMonitor = null;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public class DreamOverlayStateController implements
|
|||||||
|
|
||||||
public static final int STATE_DREAM_OVERLAY_ACTIVE = 1 << 0;
|
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_LOW_LIGHT_ACTIVE = 1 << 1;
|
||||||
|
public static final int STATE_DREAM_ENTRY_ANIMATIONS_FINISHED = 1 << 2;
|
||||||
|
|
||||||
private static final int OP_CLEAR_STATE = 1;
|
private static final int OP_CLEAR_STATE = 1;
|
||||||
private static final int OP_SET_STATE = 2;
|
private static final int OP_SET_STATE = 2;
|
||||||
@@ -202,6 +203,14 @@ public class DreamOverlayStateController implements
|
|||||||
return containsState(STATE_LOW_LIGHT_ACTIVE);
|
return containsState(STATE_LOW_LIGHT_ACTIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the dream content and dream overlay entry animations are finished.
|
||||||
|
* @return {@code true} if animations are finished, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public boolean areEntryAnimationsFinished() {
|
||||||
|
return containsState(STATE_DREAM_ENTRY_ANIMATIONS_FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean containsState(int state) {
|
private boolean containsState(int state) {
|
||||||
return (mState & state) != 0;
|
return (mState & state) != 0;
|
||||||
}
|
}
|
||||||
@@ -218,7 +227,7 @@ public class DreamOverlayStateController implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (existingState != mState) {
|
if (existingState != mState) {
|
||||||
notifyCallbacks(callback -> callback.onStateChanged());
|
notifyCallbacks(Callback::onStateChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,6 +247,15 @@ public class DreamOverlayStateController implements
|
|||||||
modifyState(active ? OP_SET_STATE : OP_CLEAR_STATE, STATE_LOW_LIGHT_ACTIVE);
|
modifyState(active ? OP_SET_STATE : OP_CLEAR_STATE, STATE_LOW_LIGHT_ACTIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether dream content and dream overlay entry animations are finished.
|
||||||
|
* @param finished {@code true} if entry animations are finished, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public void setEntryAnimationsFinished(boolean finished) {
|
||||||
|
modifyState(finished ? OP_SET_STATE : OP_CLEAR_STATE,
|
||||||
|
STATE_DREAM_ENTRY_ANIMATIONS_FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the available complication types.
|
* Returns the available complication types.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,10 +16,6 @@
|
|||||||
|
|
||||||
package com.android.systemui.dreams;
|
package com.android.systemui.dreams;
|
||||||
|
|
||||||
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
|
|
||||||
import static android.app.StatusBarManager.WINDOW_STATE_HIDING;
|
|
||||||
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
|
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.StatusBarManager;
|
import android.app.StatusBarManager;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -83,6 +79,9 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
|
|
||||||
private boolean mIsAttached;
|
private boolean mIsAttached;
|
||||||
|
|
||||||
|
// Whether dream entry animations are finished.
|
||||||
|
private boolean mEntryAnimationsFinished = false;
|
||||||
|
|
||||||
private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
|
private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
|
||||||
.clearCapabilities()
|
.clearCapabilities()
|
||||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
|
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
|
||||||
@@ -109,7 +108,9 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
new DreamOverlayStateController.Callback() {
|
new DreamOverlayStateController.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onStateChanged() {
|
public void onStateChanged() {
|
||||||
updateLowLightState();
|
mEntryAnimationsFinished =
|
||||||
|
mDreamOverlayStateController.areEntryAnimationsFinished();
|
||||||
|
updateVisibility();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -195,7 +196,6 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
mStatusBarItemsProvider.addCallback(mStatusBarItemsProviderCallback);
|
mStatusBarItemsProvider.addCallback(mStatusBarItemsProviderCallback);
|
||||||
|
|
||||||
mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback);
|
mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback);
|
||||||
updateLowLightState();
|
|
||||||
|
|
||||||
mTouchInsetSession.addViewToTracking(mView);
|
mTouchInsetSession.addViewToTracking(mView);
|
||||||
}
|
}
|
||||||
@@ -216,6 +216,26 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
mIsAttached = false;
|
mIsAttached = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets alpha of the dream overlay status bar.
|
||||||
|
*
|
||||||
|
* No-op if the dream overlay status bar should not be shown.
|
||||||
|
*/
|
||||||
|
protected void setAlpha(float alpha) {
|
||||||
|
updateVisibility();
|
||||||
|
|
||||||
|
if (mView.getVisibility() != View.VISIBLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mView.setAlpha(alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldShowStatusBar() {
|
||||||
|
return !mDreamOverlayStateController.isLowLightActive()
|
||||||
|
&& !mStatusBarWindowStateController.windowIsShowing();
|
||||||
|
}
|
||||||
|
|
||||||
private void updateWifiUnavailableStatusIcon() {
|
private void updateWifiUnavailableStatusIcon() {
|
||||||
final NetworkCapabilities capabilities =
|
final NetworkCapabilities capabilities =
|
||||||
mConnectivityManager.getNetworkCapabilities(
|
mConnectivityManager.getNetworkCapabilities(
|
||||||
@@ -235,13 +255,12 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
hasAlarm ? buildAlarmContentDescription(alarm) : null);
|
hasAlarm ? buildAlarmContentDescription(alarm) : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLowLightState() {
|
private void updateVisibility() {
|
||||||
int visibility = View.VISIBLE;
|
if (shouldShowStatusBar()) {
|
||||||
if (mDreamOverlayStateController.isLowLightActive()
|
mView.setVisibility(View.VISIBLE);
|
||||||
|| mStatusBarWindowStateController.windowIsShowing()) {
|
} else {
|
||||||
visibility = View.INVISIBLE;
|
mView.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
mView.setVisibility(visibility);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildAlarmContentDescription(AlarmManager.AlarmClockInfo alarm) {
|
private String buildAlarmContentDescription(AlarmManager.AlarmClockInfo alarm) {
|
||||||
@@ -298,21 +317,11 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onSystemStatusBarStateChanged(@StatusBarManager.WindowVisibleState int state) {
|
private void onSystemStatusBarStateChanged(@StatusBarManager.WindowVisibleState int state) {
|
||||||
mMainExecutor.execute(() -> {
|
if (!mIsAttached || !mEntryAnimationsFinished) {
|
||||||
if (!mIsAttached || mDreamOverlayStateController.isLowLightActive()) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
switch (state) {
|
mMainExecutor.execute(this::updateVisibility);
|
||||||
case WINDOW_STATE_SHOWING:
|
|
||||||
mView.setVisibility(View.INVISIBLE);
|
|
||||||
break;
|
|
||||||
case WINDOW_STATE_HIDING:
|
|
||||||
case WINDOW_STATE_HIDDEN:
|
|
||||||
mView.setVisibility(View.VISIBLE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onStatusBarItemsChanged(List<StatusBarItem> newItems) {
|
private void onStatusBarItemsChanged(List<StatusBarItem> newItems) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.view.View;
|
|||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
|
||||||
|
import com.android.systemui.dreams.DreamOverlayStateController;
|
||||||
import com.android.systemui.util.ViewController;
|
import com.android.systemui.util.ViewController;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -49,20 +50,34 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
|
|||||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
|
||||||
private final ComplicationLayoutEngine mLayoutEngine;
|
private final ComplicationLayoutEngine mLayoutEngine;
|
||||||
|
private final DreamOverlayStateController mDreamOverlayStateController;
|
||||||
private final LifecycleOwner mLifecycleOwner;
|
private final LifecycleOwner mLifecycleOwner;
|
||||||
private final ComplicationCollectionViewModel mComplicationCollectionViewModel;
|
private final ComplicationCollectionViewModel mComplicationCollectionViewModel;
|
||||||
private final HashMap<ComplicationId, Complication.ViewHolder> mComplications = new HashMap<>();
|
private final HashMap<ComplicationId, Complication.ViewHolder> mComplications = new HashMap<>();
|
||||||
|
|
||||||
|
// Whether dream entry animations are finished.
|
||||||
|
private boolean mEntryAnimationsFinished = false;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected ComplicationHostViewController(
|
protected ComplicationHostViewController(
|
||||||
@Named(SCOPED_COMPLICATIONS_LAYOUT) ConstraintLayout view,
|
@Named(SCOPED_COMPLICATIONS_LAYOUT) ConstraintLayout view,
|
||||||
ComplicationLayoutEngine layoutEngine,
|
ComplicationLayoutEngine layoutEngine,
|
||||||
|
DreamOverlayStateController dreamOverlayStateController,
|
||||||
LifecycleOwner lifecycleOwner,
|
LifecycleOwner lifecycleOwner,
|
||||||
@Named(SCOPED_COMPLICATIONS_MODEL) ComplicationCollectionViewModel viewModel) {
|
@Named(SCOPED_COMPLICATIONS_MODEL) ComplicationCollectionViewModel viewModel) {
|
||||||
super(view);
|
super(view);
|
||||||
mLayoutEngine = layoutEngine;
|
mLayoutEngine = layoutEngine;
|
||||||
mLifecycleOwner = lifecycleOwner;
|
mLifecycleOwner = lifecycleOwner;
|
||||||
mComplicationCollectionViewModel = viewModel;
|
mComplicationCollectionViewModel = viewModel;
|
||||||
|
mDreamOverlayStateController = dreamOverlayStateController;
|
||||||
|
|
||||||
|
mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onStateChanged() {
|
||||||
|
mEntryAnimationsFinished =
|
||||||
|
mDreamOverlayStateController.areEntryAnimationsFinished();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -123,6 +138,11 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
|
|||||||
final ComplicationId id = complication.getId();
|
final ComplicationId id = complication.getId();
|
||||||
final Complication.ViewHolder viewHolder = complication.getComplication()
|
final Complication.ViewHolder viewHolder = complication.getComplication()
|
||||||
.createView(complication);
|
.createView(complication);
|
||||||
|
// Complications to be added before dream entry animations are finished are set
|
||||||
|
// to invisible and are animated in.
|
||||||
|
if (!mEntryAnimationsFinished) {
|
||||||
|
viewHolder.getView().setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
mComplications.put(id, viewHolder);
|
mComplications.put(id, viewHolder);
|
||||||
if (viewHolder.getView().getParent() != null) {
|
if (viewHolder.getView().getParent() != null) {
|
||||||
Log.e(TAG, "View for complication "
|
Log.e(TAG, "View for complication "
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ public abstract class DreamOverlayModule {
|
|||||||
public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL =
|
public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL =
|
||||||
"burn_in_protection_update_interval";
|
"burn_in_protection_update_interval";
|
||||||
public static final String MILLIS_UNTIL_FULL_JITTER = "millis_until_full_jitter";
|
public static final String MILLIS_UNTIL_FULL_JITTER = "millis_until_full_jitter";
|
||||||
|
public static final String DREAM_IN_BLUR_ANIMATION_DURATION = "dream_in_blur_anim_duration";
|
||||||
|
public static final String DREAM_IN_BLUR_ANIMATION_DELAY = "dream_in_blur_anim_delay";
|
||||||
|
public static final String DREAM_IN_COMPLICATIONS_ANIMATION_DURATION =
|
||||||
|
"dream_in_complications_anim_duration";
|
||||||
|
public static final String DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY =
|
||||||
|
"dream_in_top_complications_anim_delay";
|
||||||
|
public static final String DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY =
|
||||||
|
"dream_in_bottom_complications_anim_delay";
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@Provides
|
@Provides
|
||||||
@@ -114,6 +122,51 @@ public abstract class DreamOverlayModule {
|
|||||||
return resources.getInteger(R.integer.config_dreamOverlayMillisUntilFullJitter);
|
return resources.getInteger(R.integer.config_dreamOverlayMillisUntilFullJitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration in milliseconds of the dream in un-blur animation.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@Named(DREAM_IN_BLUR_ANIMATION_DURATION)
|
||||||
|
static int providesDreamInBlurAnimationDuration(@Main Resources resources) {
|
||||||
|
return resources.getInteger(R.integer.config_dreamOverlayInBlurDurationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay in milliseconds of the dream in un-blur animation.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@Named(DREAM_IN_BLUR_ANIMATION_DELAY)
|
||||||
|
static int providesDreamInBlurAnimationDelay(@Main Resources resources) {
|
||||||
|
return resources.getInteger(R.integer.config_dreamOverlayInBlurDelayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration in milliseconds of the dream in complications fade-in animation.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@Named(DREAM_IN_COMPLICATIONS_ANIMATION_DURATION)
|
||||||
|
static int providesDreamInComplicationsAnimationDuration(@Main Resources resources) {
|
||||||
|
return resources.getInteger(R.integer.config_dreamOverlayInComplicationsDurationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay in milliseconds of the dream in top complications fade-in animation.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@Named(DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY)
|
||||||
|
static int providesDreamInTopComplicationsAnimationDelay(@Main Resources resources) {
|
||||||
|
return resources.getInteger(R.integer.config_dreamOverlayInTopComplicationsDelayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay in milliseconds of the dream in bottom complications fade-in animation.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@Named(DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY)
|
||||||
|
static int providesDreamInBottomComplicationsAnimationDelay(@Main Resources resources) {
|
||||||
|
return resources.getInteger(R.integer.config_dreamOverlayInBottomComplicationsDelayMs);
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@DreamOverlayComponent.DreamOverlayScope
|
@DreamOverlayComponent.DreamOverlayScope
|
||||||
static LifecycleOwner providesLifecycleOwner(Lazy<LifecycleRegistry> lifecycleRegistryLazy) {
|
static LifecycleOwner providesLifecycleOwner(Lazy<LifecycleRegistry> lifecycleRegistryLazy) {
|
||||||
|
|||||||
@@ -92,6 +92,12 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
BouncerCallbackInteractor mBouncerCallbackInteractor;
|
BouncerCallbackInteractor mBouncerCallbackInteractor;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
DreamOverlayAnimationsController mAnimationsController;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
DreamOverlayStateController mStateController;
|
||||||
|
|
||||||
DreamOverlayContainerViewController mController;
|
DreamOverlayContainerViewController mController;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -115,7 +121,9 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
|
|||||||
MAX_BURN_IN_OFFSET,
|
MAX_BURN_IN_OFFSET,
|
||||||
BURN_IN_PROTECTION_UPDATE_INTERVAL,
|
BURN_IN_PROTECTION_UPDATE_INTERVAL,
|
||||||
MILLIS_UNTIL_FULL_JITTER,
|
MILLIS_UNTIL_FULL_JITTER,
|
||||||
mBouncerCallbackInteractor);
|
mBouncerCallbackInteractor,
|
||||||
|
mAnimationsController,
|
||||||
|
mStateController);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -188,4 +196,31 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
|
|||||||
verify(mBlurUtils).blurRadiusOfRatio(1 - scaledFraction);
|
verify(mBlurUtils).blurRadiusOfRatio(1 - scaledFraction);
|
||||||
verify(mBlurUtils).applyBlur(mViewRoot, (int) blurRadius, false);
|
verify(mBlurUtils).applyBlur(mViewRoot, (int) blurRadius, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartDreamEntryAnimationsOnAttachedNonLowLight() {
|
||||||
|
when(mStateController.isLowLightActive()).thenReturn(false);
|
||||||
|
|
||||||
|
mController.onViewAttached();
|
||||||
|
|
||||||
|
verify(mAnimationsController).startEntryAnimations(mDreamOverlayContainerView);
|
||||||
|
verify(mAnimationsController, never()).cancelRunningEntryAnimations();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNeverStartDreamEntryAnimationsOnAttachedForLowLight() {
|
||||||
|
when(mStateController.isLowLightActive()).thenReturn(true);
|
||||||
|
|
||||||
|
mController.onViewAttached();
|
||||||
|
|
||||||
|
verify(mAnimationsController, never()).startEntryAnimations(mDreamOverlayContainerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCancelDreamEntryAnimationsOnDetached() {
|
||||||
|
mController.onViewAttached();
|
||||||
|
mController.onViewDetached();
|
||||||
|
|
||||||
|
verify(mAnimationsController).cancelRunningEntryAnimations();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,6 +253,7 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
|
|||||||
verify(mLifecycleRegistry).setCurrentState(Lifecycle.State.DESTROYED);
|
verify(mLifecycleRegistry).setCurrentState(Lifecycle.State.DESTROYED);
|
||||||
verify(mStateController).setOverlayActive(false);
|
verify(mStateController).setOverlayActive(false);
|
||||||
verify(mStateController).setLowLightActive(false);
|
verify(mStateController).setLowLightActive(false);
|
||||||
|
verify(mStateController).setEntryAnimationsFinished(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -234,4 +234,20 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
|
|||||||
verify(mCallback, times(1)).onStateChanged();
|
verify(mCallback, times(1)).onStateChanged();
|
||||||
assertThat(stateController.isLowLightActive()).isTrue();
|
assertThat(stateController.isLowLightActive()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyEntryAnimationsFinishedChanged() {
|
||||||
|
final DreamOverlayStateController stateController =
|
||||||
|
new DreamOverlayStateController(mExecutor);
|
||||||
|
|
||||||
|
stateController.addCallback(mCallback);
|
||||||
|
mExecutor.runAllReady();
|
||||||
|
assertThat(stateController.areEntryAnimationsFinished()).isFalse();
|
||||||
|
|
||||||
|
stateController.setEntryAnimationsFinished(true);
|
||||||
|
mExecutor.runAllReady();
|
||||||
|
|
||||||
|
verify(mCallback, times(1)).onStateChanged();
|
||||||
|
assertThat(stateController.areEntryAnimationsFinished()).isTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,20 @@ package com.android.systemui.dreams;
|
|||||||
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
|
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
|
||||||
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
|
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.ArgumentMatchers.isNull;
|
import static org.mockito.ArgumentMatchers.isNull;
|
||||||
|
import static org.mockito.Mockito.doCallRealMethod;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.reset;
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.hardware.SensorPrivacyManager;
|
import android.hardware.SensorPrivacyManager;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
@@ -55,6 +59,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
@@ -69,7 +74,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
"{count, plural, =1 {# notification} other {# notifications}}";
|
"{count, plural, =1 {# notification} other {# notifications}}";
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
DreamOverlayStatusBarView mView;
|
MockDreamOverlayStatusBarView mView;
|
||||||
@Mock
|
@Mock
|
||||||
ConnectivityManager mConnectivityManager;
|
ConnectivityManager mConnectivityManager;
|
||||||
@Mock
|
@Mock
|
||||||
@@ -105,6 +110,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
DreamOverlayStateController mDreamOverlayStateController;
|
DreamOverlayStateController mDreamOverlayStateController;
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<DreamOverlayStateController.Callback> mCallbackCaptor;
|
||||||
|
|
||||||
private final Executor mMainExecutor = Runnable::run;
|
private final Executor mMainExecutor = Runnable::run;
|
||||||
|
|
||||||
DreamOverlayStatusBarViewController mController;
|
DreamOverlayStatusBarViewController mController;
|
||||||
@@ -115,6 +123,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
when(mResources.getString(R.string.dream_overlay_status_bar_notification_indicator))
|
when(mResources.getString(R.string.dream_overlay_status_bar_notification_indicator))
|
||||||
.thenReturn(NOTIFICATION_INDICATOR_FORMATTER_STRING);
|
.thenReturn(NOTIFICATION_INDICATOR_FORMATTER_STRING);
|
||||||
|
doCallRealMethod().when(mView).setVisibility(anyInt());
|
||||||
|
doCallRealMethod().when(mView).getVisibility();
|
||||||
|
|
||||||
mController = new DreamOverlayStatusBarViewController(
|
mController = new DreamOverlayStatusBarViewController(
|
||||||
mView,
|
mView,
|
||||||
@@ -454,12 +464,10 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
public void testStatusBarHiddenWhenSystemStatusBarShown() {
|
public void testStatusBarHiddenWhenSystemStatusBarShown() {
|
||||||
mController.onViewAttached();
|
mController.onViewAttached();
|
||||||
|
|
||||||
final ArgumentCaptor<StatusBarWindowStateListener>
|
updateEntryAnimationsFinished();
|
||||||
callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class);
|
updateStatusBarWindowState(true);
|
||||||
verify(mStatusBarWindowStateController).addListener(callbackCapture.capture());
|
|
||||||
callbackCapture.getValue().onStatusBarWindowStateChanged(WINDOW_STATE_SHOWING);
|
|
||||||
|
|
||||||
verify(mView).setVisibility(View.INVISIBLE);
|
assertThat(mView.getVisibility()).isEqualTo(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -467,28 +475,42 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
mController.onViewAttached();
|
mController.onViewAttached();
|
||||||
reset(mView);
|
reset(mView);
|
||||||
|
|
||||||
final ArgumentCaptor<StatusBarWindowStateListener>
|
updateEntryAnimationsFinished();
|
||||||
callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class);
|
updateStatusBarWindowState(false);
|
||||||
verify(mStatusBarWindowStateController).addListener(callbackCapture.capture());
|
|
||||||
callbackCapture.getValue().onStatusBarWindowStateChanged(WINDOW_STATE_HIDDEN);
|
|
||||||
|
|
||||||
verify(mView).setVisibility(View.VISIBLE);
|
assertThat(mView.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnattachedStatusBarVisibilityUnchangedWhenSystemStatusBarHidden() {
|
public void testUnattachedStatusBarVisibilityUnchangedWhenSystemStatusBarHidden() {
|
||||||
mController.onViewAttached();
|
mController.onViewAttached();
|
||||||
|
updateEntryAnimationsFinished();
|
||||||
mController.onViewDetached();
|
mController.onViewDetached();
|
||||||
reset(mView);
|
reset(mView);
|
||||||
|
|
||||||
final ArgumentCaptor<StatusBarWindowStateListener>
|
updateStatusBarWindowState(true);
|
||||||
callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class);
|
|
||||||
verify(mStatusBarWindowStateController).addListener(callbackCapture.capture());
|
|
||||||
callbackCapture.getValue().onStatusBarWindowStateChanged(WINDOW_STATE_SHOWING);
|
|
||||||
|
|
||||||
verify(mView, never()).setVisibility(anyInt());
|
verify(mView, never()).setVisibility(anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoChangeToVisibilityBeforeDreamStartedWhenStatusBarHidden() {
|
||||||
|
mController.onViewAttached();
|
||||||
|
|
||||||
|
// Trigger status bar window state change.
|
||||||
|
final StatusBarWindowStateListener listener = updateStatusBarWindowState(false);
|
||||||
|
|
||||||
|
// Verify no visibility change because dream not started.
|
||||||
|
verify(mView, never()).setVisibility(anyInt());
|
||||||
|
|
||||||
|
// Dream entry animations finished.
|
||||||
|
updateEntryAnimationsFinished();
|
||||||
|
|
||||||
|
// Trigger another status bar window state change, and verify visibility change.
|
||||||
|
listener.onStatusBarWindowStateChanged(WINDOW_STATE_HIDDEN);
|
||||||
|
assertThat(mView.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExtraStatusBarItemSetWhenItemsChange() {
|
public void testExtraStatusBarItemSetWhenItemsChange() {
|
||||||
mController.onViewAttached();
|
mController.onViewAttached();
|
||||||
@@ -507,16 +529,75 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
public void testLowLightHidesStatusBar() {
|
public void testLowLightHidesStatusBar() {
|
||||||
when(mDreamOverlayStateController.isLowLightActive()).thenReturn(true);
|
when(mDreamOverlayStateController.isLowLightActive()).thenReturn(true);
|
||||||
mController.onViewAttached();
|
mController.onViewAttached();
|
||||||
|
updateEntryAnimationsFinished();
|
||||||
|
|
||||||
verify(mView).setVisibility(View.INVISIBLE);
|
|
||||||
reset(mView);
|
|
||||||
|
|
||||||
when(mDreamOverlayStateController.isLowLightActive()).thenReturn(false);
|
|
||||||
final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
|
final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
|
||||||
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
|
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
|
||||||
verify(mDreamOverlayStateController).addCallback(callbackCapture.capture());
|
verify(mDreamOverlayStateController).addCallback(callbackCapture.capture());
|
||||||
callbackCapture.getValue().onStateChanged();
|
callbackCapture.getValue().onStateChanged();
|
||||||
|
|
||||||
verify(mView).setVisibility(View.VISIBLE);
|
assertThat(mView.getVisibility()).isEqualTo(View.INVISIBLE);
|
||||||
|
reset(mView);
|
||||||
|
|
||||||
|
when(mDreamOverlayStateController.isLowLightActive()).thenReturn(false);
|
||||||
|
callbackCapture.getValue().onStateChanged();
|
||||||
|
|
||||||
|
assertThat(mView.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoChangeToVisibilityBeforeDreamStartedWhenLowLightStateChange() {
|
||||||
|
when(mDreamOverlayStateController.isLowLightActive()).thenReturn(false);
|
||||||
|
mController.onViewAttached();
|
||||||
|
|
||||||
|
// No change to visibility because dream not fully started.
|
||||||
|
verify(mView, never()).setVisibility(anyInt());
|
||||||
|
|
||||||
|
// Dream entry animations finished.
|
||||||
|
updateEntryAnimationsFinished();
|
||||||
|
|
||||||
|
// Trigger state change and verify visibility changed.
|
||||||
|
final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
|
||||||
|
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
|
||||||
|
verify(mDreamOverlayStateController).addCallback(callbackCapture.capture());
|
||||||
|
callbackCapture.getValue().onStateChanged();
|
||||||
|
|
||||||
|
assertThat(mView.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StatusBarWindowStateListener updateStatusBarWindowState(boolean show) {
|
||||||
|
when(mStatusBarWindowStateController.windowIsShowing()).thenReturn(show);
|
||||||
|
final ArgumentCaptor<StatusBarWindowStateListener>
|
||||||
|
callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class);
|
||||||
|
verify(mStatusBarWindowStateController).addListener(callbackCapture.capture());
|
||||||
|
final StatusBarWindowStateListener listener = callbackCapture.getValue();
|
||||||
|
listener.onStatusBarWindowStateChanged(show ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN);
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateEntryAnimationsFinished() {
|
||||||
|
when(mDreamOverlayStateController.areEntryAnimationsFinished()).thenReturn(true);
|
||||||
|
|
||||||
|
verify(mDreamOverlayStateController).addCallback(mCallbackCaptor.capture());
|
||||||
|
final DreamOverlayStateController.Callback callback = mCallbackCaptor.getValue();
|
||||||
|
callback.onStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MockDreamOverlayStatusBarView extends DreamOverlayStatusBarView {
|
||||||
|
private int mVisibility = View.VISIBLE;
|
||||||
|
|
||||||
|
private MockDreamOverlayStatusBarView(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVisibility(int visibility) {
|
||||||
|
mVisibility = visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVisibility() {
|
||||||
|
return mVisibility;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package com.android.systemui.dreams.complication;
|
package com.android.systemui.dreams.complication;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -29,16 +30,18 @@ import androidx.lifecycle.Observer;
|
|||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.dreams.DreamOverlayStateController;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@@ -77,9 +80,20 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
ComplicationLayoutParams mComplicationLayoutParams;
|
ComplicationLayoutParams mComplicationLayoutParams;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
DreamOverlayStateController mDreamOverlayStateController;
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<Observer<Collection<ComplicationViewModel>>> mObserverCaptor;
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<DreamOverlayStateController.Callback> mCallbackCaptor;
|
||||||
|
|
||||||
@Complication.Category
|
@Complication.Category
|
||||||
static final int COMPLICATION_CATEGORY = Complication.CATEGORY_SYSTEM;
|
static final int COMPLICATION_CATEGORY = Complication.CATEGORY_SYSTEM;
|
||||||
|
|
||||||
|
private ComplicationHostViewController mController;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
@@ -91,6 +105,15 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
|
|||||||
when(mViewHolder.getCategory()).thenReturn(COMPLICATION_CATEGORY);
|
when(mViewHolder.getCategory()).thenReturn(COMPLICATION_CATEGORY);
|
||||||
when(mViewHolder.getLayoutParams()).thenReturn(mComplicationLayoutParams);
|
when(mViewHolder.getLayoutParams()).thenReturn(mComplicationLayoutParams);
|
||||||
when(mComplicationView.getParent()).thenReturn(mComplicationHostView);
|
when(mComplicationView.getParent()).thenReturn(mComplicationHostView);
|
||||||
|
|
||||||
|
mController = new ComplicationHostViewController(
|
||||||
|
mComplicationHostView,
|
||||||
|
mLayoutEngine,
|
||||||
|
mDreamOverlayStateController,
|
||||||
|
mLifecycleOwner,
|
||||||
|
mViewModel);
|
||||||
|
|
||||||
|
mController.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,25 +121,12 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testViewModelObservation() {
|
public void testViewModelObservation() {
|
||||||
final ArgumentCaptor<Observer<Collection<ComplicationViewModel>>> observerArgumentCaptor =
|
|
||||||
ArgumentCaptor.forClass(Observer.class);
|
|
||||||
final ComplicationHostViewController controller = new ComplicationHostViewController(
|
|
||||||
mComplicationHostView,
|
|
||||||
mLayoutEngine,
|
|
||||||
mLifecycleOwner,
|
|
||||||
mViewModel);
|
|
||||||
|
|
||||||
controller.init();
|
|
||||||
|
|
||||||
verify(mComplicationViewModelLiveData).observe(eq(mLifecycleOwner),
|
|
||||||
observerArgumentCaptor.capture());
|
|
||||||
|
|
||||||
final Observer<Collection<ComplicationViewModel>> observer =
|
final Observer<Collection<ComplicationViewModel>> observer =
|
||||||
observerArgumentCaptor.getValue();
|
captureComplicationViewModelsObserver();
|
||||||
|
|
||||||
// Add complication and ensure it is added to the view.
|
// Add a complication and ensure it is added to the view.
|
||||||
final HashSet<ComplicationViewModel> complications = new HashSet<>(
|
final HashSet<ComplicationViewModel> complications = new HashSet<>(
|
||||||
Arrays.asList(mComplicationViewModel));
|
Collections.singletonList(mComplicationViewModel));
|
||||||
observer.onChanged(complications);
|
observer.onChanged(complications);
|
||||||
|
|
||||||
verify(mLayoutEngine).addComplication(eq(mComplicationId), eq(mComplicationView),
|
verify(mLayoutEngine).addComplication(eq(mComplicationId), eq(mComplicationView),
|
||||||
@@ -127,4 +137,48 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
verify(mLayoutEngine).removeComplication(eq(mComplicationId));
|
verify(mLayoutEngine).removeComplication(eq(mComplicationId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewComplicationsBeforeEntryAnimationsFinishSetToInvisible() {
|
||||||
|
final Observer<Collection<ComplicationViewModel>> observer =
|
||||||
|
captureComplicationViewModelsObserver();
|
||||||
|
|
||||||
|
// Add a complication before entry animations are finished.
|
||||||
|
final HashSet<ComplicationViewModel> complications = new HashSet<>(
|
||||||
|
Collections.singletonList(mComplicationViewModel));
|
||||||
|
observer.onChanged(complications);
|
||||||
|
|
||||||
|
// The complication view should be set to invisible.
|
||||||
|
verify(mComplicationView).setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewComplicationsAfterEntryAnimationsFinishNotSetToInvisible() {
|
||||||
|
final Observer<Collection<ComplicationViewModel>> observer =
|
||||||
|
captureComplicationViewModelsObserver();
|
||||||
|
|
||||||
|
// Dream entry animations finished.
|
||||||
|
when(mDreamOverlayStateController.areEntryAnimationsFinished()).thenReturn(true);
|
||||||
|
final DreamOverlayStateController.Callback stateCallback = captureOverlayStateCallback();
|
||||||
|
stateCallback.onStateChanged();
|
||||||
|
|
||||||
|
// Add a complication after entry animations are finished.
|
||||||
|
final HashSet<ComplicationViewModel> complications = new HashSet<>(
|
||||||
|
Collections.singletonList(mComplicationViewModel));
|
||||||
|
observer.onChanged(complications);
|
||||||
|
|
||||||
|
// The complication view should not be set to invisible.
|
||||||
|
verify(mComplicationView, never()).setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Observer<Collection<ComplicationViewModel>> captureComplicationViewModelsObserver() {
|
||||||
|
verify(mComplicationViewModelLiveData).observe(eq(mLifecycleOwner),
|
||||||
|
mObserverCaptor.capture());
|
||||||
|
return mObserverCaptor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DreamOverlayStateController.Callback captureOverlayStateCallback() {
|
||||||
|
verify(mDreamOverlayStateController).addCallback(mCallbackCaptor.capture());
|
||||||
|
return mCallbackCaptor.getValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user