Merge "Implement dream complication motion/fade when transitionting to bouncer." into tm-dev

This commit is contained in:
Lucas Silva
2022-04-01 19:32:34 +00:00
committed by Android (Google) Code Review
7 changed files with 171 additions and 15 deletions

View File

@@ -1429,6 +1429,8 @@
<!-- The margin applied between complications -->
<dimen name="dream_overlay_complication_margin">0dp</dimen>
<dimen name="dream_overlay_y_offset">80dp</dimen>
<dimen name="status_view_margin_horizontal">0dp</dimen>
<!-- Media output broadcast dialog QR code picture size -->

View File

@@ -46,4 +46,24 @@ object BouncerPanelExpansionCalculator {
fun getKeyguardClockScaledExpansion(fraction: Float): Float {
return MathUtils.constrain((fraction - 0.7f) / 0.3f, 0f, 1f)
}
/**
* Scale the position of the dream complications.
*/
@JvmStatic
fun getDreamYPositionScaledExpansion(fraction: Float): Float {
return when {
fraction >= 0.98f -> 1f
fraction < 0.93 -> 0f
else -> (fraction - 0.93f) / 0.05f
}
}
/**
* Scale the alpha of the dream complications.
*/
@JvmStatic
fun getDreamAlphaScaledExpansion(fraction: Float): Float {
return MathUtils.constrain((fraction - 0.94f) / 0.06f, 0f, 1f)
}
}

View File

@@ -16,14 +16,21 @@
package com.android.systemui.dreams;
import static com.android.keyguard.BouncerPanelExpansionCalculator.getBackScrimScaledExpansion;
import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamAlphaScaledExpansion;
import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamYPositionScaledExpansion;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_BOTTOM;
import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_TOP;
import android.content.res.Resources;
import android.os.Handler;
import android.util.MathUtils;
import android.view.View;
import android.view.ViewGroup;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
@@ -33,6 +40,8 @@ import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.ViewController;
import java.util.Arrays;
import javax.inject.Inject;
import javax.inject.Named;
@@ -63,6 +72,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
// Main thread handler used to schedule periodic tasks (e.g. burn-in protection updates).
private final Handler mHandler;
private final int mDreamOverlayMaxTranslationY;
private long mJitterStartTimeMillis;
@@ -93,13 +103,9 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
@Override
public void onExpansionChanged(float bouncerHideAmount) {
if (!mBouncerAnimating) return;
final float scaledFraction =
BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(
bouncerHideAmount);
final int blurRadius =
(int) mBlurUtils.blurRadiusOfRatio(1 - scaledFraction);
updateTransitionState(blurRadius, scaledFraction);
if (mBouncerAnimating) {
updateTransitionState(bouncerHideAmount);
}
}
@Override
@@ -107,7 +113,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
// The bouncer may be hidden abruptly without triggering onExpansionChanged.
// In this case, we should reset the transition state.
if (!isVisible) {
updateTransitionState(0, 1f);
updateTransitionState(1f);
}
}
};
@@ -121,6 +127,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
BlurUtils blurUtils,
@Main Handler handler,
@Main Resources resources,
@Named(DreamOverlayModule.MAX_BURN_IN_OFFSET) int maxBurnInOffset,
@Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
burnInProtectionUpdateInterval,
@@ -132,6 +139,8 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
mBlurUtils = blurUtils;
mComplicationHostViewController = complicationHostViewController;
mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize(
R.dimen.dream_overlay_y_offset);
final View view = mComplicationHostViewController.getView();
mDreamOverlayContentView.addView(view,
@@ -196,8 +205,31 @@ 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);
private void updateTransitionState(float bouncerHideAmount) {
for (int position : Arrays.asList(POSITION_TOP, POSITION_BOTTOM)) {
final float alpha = getAlpha(position, bouncerHideAmount);
final float translationY = getTranslationY(position, bouncerHideAmount);
mComplicationHostViewController.getViewsAtPosition(position).forEach(v -> {
v.setAlpha(alpha);
v.setTranslationY(translationY);
});
}
mBlurUtils.applyBlur(mView.getViewRootImpl(),
(int) mBlurUtils.blurRadiusOfRatio(
1 - getBackScrimScaledExpansion(bouncerHideAmount)), false);
}
private static float getAlpha(int position, float expansion) {
return Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
position == POSITION_TOP ? getDreamAlphaScaledExpansion(expansion)
: getBackScrimScaledExpansion(expansion + 0.03f));
}
private float getTranslationY(int position, float expansion) {
final float fraction = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
position == POSITION_TOP ? getDreamYPositionScaledExpansion(expansion)
: getBackScrimScaledExpansion(expansion + 0.03f));
return MathUtils.lerp(-mDreamOverlayMaxTranslationY, 0, fraction);
}
}

View File

@@ -31,6 +31,7 @@ import com.android.systemui.util.ViewController;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -144,4 +145,11 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
public View getView() {
return mView;
}
/**
* Gets an unordered list of all the views at a particular position.
*/
public List<View> getViewsAtPosition(@ComplicationLayoutParams.Position int position) {
return mLayoutEngine.getViewsAtPosition(position);
}
}

View File

@@ -32,6 +32,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Constraints;
import com.android.systemui.R;
import com.android.systemui.dreams.complication.ComplicationLayoutParams.Position;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.touch.TouchInsetManager;
@@ -39,7 +40,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Named;
@@ -378,6 +381,14 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll
directionGroup.updateViews(head.getView());
}
}
private ArrayList<ViewEntry> getViews() {
final ArrayList<ViewEntry> views = new ArrayList<>();
for (DirectionGroup directionGroup : mDirectionGroups.values()) {
views.addAll(directionGroup.getViews());
}
return views;
}
}
/**
@@ -454,6 +465,10 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll
groupHead = viewEntry.getView();
}
}
private List<ViewEntry> getViews() {
return mViews;
}
}
private final ConstraintLayout mLayout;
@@ -551,4 +566,15 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll
entry.remove();
return true;
}
/**
* Gets an unordered list of all the views at a particular position.
*/
public List<View> getViewsAtPosition(@Position int position) {
return mPositions.entrySet().stream()
.filter(entry -> (entry.getKey() & position) == position)
.flatMap(entry -> entry.getValue().getViews().stream())
.map(ViewEntry::getView)
.collect(Collectors.toList());
}
}

View File

@@ -107,6 +107,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mStatusBarKeyguardViewManager,
mBlurUtils,
mHandler,
mResources,
MAX_BURN_IN_OFFSET,
BURN_IN_PROTECTION_UPDATE_INTERVAL,
MILLIS_UNTIL_FULL_JITTER);
@@ -160,11 +161,10 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
bouncerExpansionCaptor.getValue().onExpansionChanged(0.5f);
verify(mBlurUtils, never()).applyBlur(eq(mViewRoot), anyInt(), eq(false));
verify(mDreamOverlayContainerView, never()).setAlpha(anyFloat());
}
@Test
public void testBouncerAnimation_updateBlurAndAlpha() {
public void testBouncerAnimation_updateBlur() {
final ArgumentCaptor<BouncerExpansionCallback> bouncerExpansionCaptor =
ArgumentCaptor.forClass(BouncerExpansionCallback.class);
mController.onViewAttached();
@@ -182,6 +182,5 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
bouncerExpansionCaptor.getValue().onExpansionChanged(bouncerHideAmount);
verify(mBlurUtils).blurRadiusOfRatio(1 - scaledFraction);
verify(mBlurUtils).applyBlur(mViewRoot, (int) blurRadius, false);
verify(mDreamOverlayContainerView).setAlpha(scaledFraction);
}
}

View File

@@ -40,7 +40,10 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -448,4 +451,70 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase {
verify(firstViewInfo.view, never()).getParent();
verify(mLayout, never()).removeView(firstViewInfo.view);
}
@Test
public void testGetViews() {
final ComplicationLayoutEngine engine =
new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
final ViewInfo topEndView = new ViewInfo(
new ComplicationLayoutParams(
100,
100,
ComplicationLayoutParams.POSITION_TOP
| ComplicationLayoutParams.POSITION_END,
ComplicationLayoutParams.DIRECTION_DOWN,
0),
Complication.CATEGORY_STANDARD,
mLayout);
addComplication(engine, topEndView);
final ViewInfo topStartView = new ViewInfo(
new ComplicationLayoutParams(
100,
100,
ComplicationLayoutParams.POSITION_TOP
| ComplicationLayoutParams.POSITION_START,
ComplicationLayoutParams.DIRECTION_DOWN,
0),
Complication.CATEGORY_SYSTEM,
mLayout);
addComplication(engine, topStartView);
final ViewInfo bottomEndView = new ViewInfo(
new ComplicationLayoutParams(
100,
100,
ComplicationLayoutParams.POSITION_BOTTOM
| ComplicationLayoutParams.POSITION_END,
ComplicationLayoutParams.DIRECTION_START,
1),
Complication.CATEGORY_SYSTEM,
mLayout);
addComplication(engine, bottomEndView);
verifyViewsAtPosition(engine, ComplicationLayoutParams.POSITION_TOP, topStartView,
topEndView);
verifyViewsAtPosition(engine,
ComplicationLayoutParams.POSITION_TOP | ComplicationLayoutParams.POSITION_START,
topStartView);
verifyViewsAtPosition(engine,
ComplicationLayoutParams.POSITION_BOTTOM,
bottomEndView);
}
private void verifyViewsAtPosition(ComplicationLayoutEngine engine, int position,
ViewInfo... views) {
final List<Integer> idList = engine.getViewsAtPosition(position).stream()
.map(View::getId)
.collect(Collectors.toList());
assertThat(idList).containsExactlyElementsIn(
Arrays.stream(views)
.map(viewInfo -> viewInfo.view.getId())
.collect(Collectors.toList()));
}
}