Merge "Implement dream to bouncer animation." into tm-dev
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user