Merge "Implement dream to bouncer animation." into tm-dev

This commit is contained in:
Lucas Silva
2022-03-23 15:03:23 +00:00
committed by Android (Google) Code Review
4 changed files with 204 additions and 9 deletions

View File

@@ -27,6 +27,9 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
@@ -38,6 +41,8 @@ import javax.inject.Named;
@DreamOverlayComponent.DreamOverlayScope
public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
private final DreamOverlayStatusBarViewController mStatusBarViewController;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final BlurUtils mBlurUtils;
private final ComplicationHostViewController mComplicationHostViewController;
@@ -60,12 +65,57 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
private long mJitterStartTimeMillis;
private boolean mBouncerAnimating;
private final KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback =
new KeyguardBouncer.BouncerExpansionCallback() {
@Override
public void onStartingToShow() {
mBouncerAnimating = true;
}
@Override
public void onStartingToHide() {
mBouncerAnimating = true;
}
@Override
public void onFullyHidden() {
mBouncerAnimating = false;
}
@Override
public void onFullyShown() {
mBouncerAnimating = false;
}
@Override
public void onExpansionChanged(float bouncerHideAmount) {
if (!mBouncerAnimating) return;
final int blurRadius =
(int) mBlurUtils.blurRadiusOfRatio(1 - bouncerHideAmount);
updateTransitionState(blurRadius, bouncerHideAmount);
}
@Override
public void onVisibilityChanged(boolean isVisible) {
// The bouncer may be hidden abruptly without triggering onExpansionChanged.
// In this case, we should reset the transition state.
if (!isVisible) {
updateTransitionState(0, 1f);
}
}
};
@Inject
public DreamOverlayContainerViewController(
DreamOverlayContainerView containerView,
ComplicationHostViewController complicationHostViewController,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
DreamOverlayStatusBarViewController statusBarViewController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
BlurUtils blurUtils,
@Main Handler handler,
@Named(DreamOverlayModule.MAX_BURN_IN_OFFSET) int maxBurnInOffset,
@Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
@@ -74,6 +124,8 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mBlurUtils = blurUtils;
mComplicationHostViewController = complicationHostViewController;
final View view = mComplicationHostViewController.getView();
@@ -98,11 +150,19 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
protected void onViewAttached() {
mJitterStartTimeMillis = System.currentTimeMillis();
mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getBouncer();
if (bouncer != null) {
bouncer.addBouncerExpansionCallback(mBouncerExpansionCallback);
}
}
@Override
protected void onViewDetached() {
mHandler.removeCallbacks(this::updateBurnInOffsets);
final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getBouncer();
if (bouncer != null) {
bouncer.removeBouncerExpansionCallback(mBouncerExpansionCallback);
}
}
View getContainerView() {
@@ -131,4 +191,9 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
}
private void updateTransitionState(int blurRadiusPixels, float alpha) {
mBlurUtils.applyBlur(mView.getViewRootImpl(), blurRadiusPixels, false);
mView.setAlpha(alpha);
}
}

View File

@@ -606,11 +606,47 @@ public class KeyguardBouncer {
mResetCallbacks.remove(callback);
}
/**
* Adds a callback to listen to bouncer expansion updates.
*/
public void addBouncerExpansionCallback(BouncerExpansionCallback callback) {
if (!mExpansionCallbacks.contains(callback)) {
mExpansionCallbacks.add(callback);
}
}
/**
* Removes a previously added callback. If the callback was never added, this methood
* does nothing.
*/
public void removeBouncerExpansionCallback(BouncerExpansionCallback callback) {
mExpansionCallbacks.remove(callback);
}
public interface BouncerExpansionCallback {
void onFullyShown();
void onStartingToHide();
void onStartingToShow();
void onFullyHidden();
/**
* Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_VISIBLE}.
*/
default void onFullyShown() {
}
/**
* Invoked when the bouncer is starting to transition to a hidden state.
*/
default void onStartingToHide() {
}
/**
* Invoked when the bouncer is starting to transition to a visible state.
*/
default void onStartingToShow() {
}
/**
* Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_HIDDEN}.
*/
default void onFullyHidden() {
}
/**
* From 0f {@link KeyguardBouncer#EXPANSION_VISIBLE} when fully visible

View File

@@ -17,7 +17,10 @@
package com.android.systemui.dreams;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -25,12 +28,17 @@ import android.content.res.Resources;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
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.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import org.junit.Before;
import org.junit.Test;
@@ -67,6 +75,18 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
@Mock
Handler mHandler;
@Mock
BlurUtils mBlurUtils;
@Mock
StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
KeyguardBouncer mBouncer;
@Mock
ViewRootImpl mViewRoot;
DreamOverlayContainerViewController mController;
@Before
@@ -75,12 +95,16 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
when(mDreamOverlayContainerView.getResources()).thenReturn(mResources);
when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
when(mStatusBarKeyguardViewManager.getBouncer()).thenReturn(mBouncer);
when(mDreamOverlayContainerView.getViewRootImpl()).thenReturn(mViewRoot);
mController = new DreamOverlayContainerViewController(
mDreamOverlayContainerView,
mComplicationHostViewController,
mDreamOverlayContentView,
mDreamOverlayStatusBarViewController,
mStatusBarKeyguardViewManager,
mBlurUtils,
mHandler,
MAX_BURN_IN_OFFSET,
BURN_IN_PROTECTION_UPDATE_INTERVAL,
@@ -125,4 +149,34 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
runnableCaptor.getValue().run();
verify(mHandler).postDelayed(runnableCaptor.getValue(), BURN_IN_PROTECTION_UPDATE_INTERVAL);
}
@Test
public void testBouncerAnimation_doesNotApply() {
final ArgumentCaptor<BouncerExpansionCallback> bouncerExpansionCaptor =
ArgumentCaptor.forClass(BouncerExpansionCallback.class);
mController.onViewAttached();
verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture());
bouncerExpansionCaptor.getValue().onExpansionChanged(0.5f);
verify(mBlurUtils, never()).applyBlur(eq(mViewRoot), anyInt(), eq(false));
verify(mDreamOverlayContainerView, never()).setAlpha(anyFloat());
}
@Test
public void testBouncerAnimation_updateBlurAndAlpha() {
final ArgumentCaptor<BouncerExpansionCallback> bouncerExpansionCaptor =
ArgumentCaptor.forClass(BouncerExpansionCallback.class);
mController.onViewAttached();
verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture());
final float blurRadius = 1337f;
when(mBlurUtils.blurRadiusOfRatio(anyFloat())).thenReturn(blurRadius);
bouncerExpansionCaptor.getValue().onStartingToShow();
final float bouncerHideAmount = 0.1f;
bouncerExpansionCaptor.getValue().onExpansionChanged(bouncerHideAmount);
verify(mBlurUtils).blurRadiusOfRatio(1 - bouncerHideAmount);
verify(mBlurUtils).applyBlur(mViewRoot, (int) blurRadius, false);
verify(mDreamOverlayContainerView).setAlpha(bouncerHideAmount);
}
}

View File

@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.statusbar.phone.KeyguardBouncer.EXPANSION_HIDDEN;
import static com.android.systemui.statusbar.phone.KeyguardBouncer.EXPANSION_VISIBLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -24,9 +27,11 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -53,6 +58,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Assert;
@@ -62,6 +68,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -79,7 +86,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Mock
private KeyguardHostViewController mKeyguardHostViewController;
@Mock
private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback;
private BouncerExpansionCallback mExpansionCallback;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
@@ -197,11 +204,11 @@ public class KeyguardBouncerTest extends SysuiTestCase {
mBouncer.ensureView();
mBouncer.setExpansion(0.5f);
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
mBouncer.setExpansion(EXPANSION_HIDDEN);
verify(mFalsingCollector).onBouncerHidden();
verify(mExpansionCallback).onFullyHidden();
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
mBouncer.setExpansion(EXPANSION_VISIBLE);
verify(mFalsingCollector).onBouncerShown();
verify(mExpansionCallback).onFullyShown();
@@ -410,11 +417,11 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Test
public void testInTransit_whenTranslation() {
mBouncer.show(true);
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
mBouncer.setExpansion(EXPANSION_HIDDEN);
assertThat(mBouncer.inTransit()).isFalse();
mBouncer.setExpansion(0.5f);
assertThat(mBouncer.inTransit()).isTrue();
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
mBouncer.setExpansion(EXPANSION_VISIBLE);
assertThat(mBouncer.inTransit()).isFalse();
}
@@ -435,4 +442,37 @@ public class KeyguardBouncerTest extends SysuiTestCase {
verify(mKeyguardHostViewController).updateKeyguardPosition(1.0f);
}
@Test
public void testExpansion_notifiesCallback() {
mBouncer.ensureView();
mBouncer.setExpansion(0.5f);
final BouncerExpansionCallback callback = mock(BouncerExpansionCallback.class);
mBouncer.addBouncerExpansionCallback(callback);
mBouncer.setExpansion(EXPANSION_HIDDEN);
verify(callback).onFullyHidden();
verify(callback).onExpansionChanged(EXPANSION_HIDDEN);
Mockito.clearInvocations(callback);
mBouncer.setExpansion(EXPANSION_VISIBLE);
verify(callback).onFullyShown();
verify(callback).onExpansionChanged(EXPANSION_VISIBLE);
Mockito.clearInvocations(callback);
float bouncerHideAmount = 0.9f;
// Ensure the callback only triggers once despite multiple calls to setExpansion
// with the same value.
mBouncer.setExpansion(bouncerHideAmount);
mBouncer.setExpansion(bouncerHideAmount);
verify(callback, times(1)).onStartingToHide();
verify(callback, times(1)).onExpansionChanged(bouncerHideAmount);
Mockito.clearInvocations(callback);
mBouncer.removeBouncerExpansionCallback(callback);
bouncerHideAmount = 0.5f;
mBouncer.setExpansion(bouncerHideAmount);
verify(callback, never()).onExpansionChanged(bouncerHideAmount);
}
}