Fix a bug with jittering dream overlay.
The first jitter causes all the dream overlay views to jump noticeably. The issues was that the first jitter happens after the views have appeared on screen. The solution is to jitter immediately so that the views are already in their initial jitter position before they become visible. Test: atest DreamOverlayContainerViewControllerTest Bug: 220182090 Change-Id: Ia62a5cf8d314a8617eaa522b51be99f61aef8b99
This commit is contained in:
@@ -695,4 +695,7 @@
|
||||
|
||||
<!-- How often in milliseconds to jitter the dream overlay in order to avoid burn-in. -->
|
||||
<integer name="config_dreamOverlayBurnInProtectionUpdateIntervalMillis">500</integer>
|
||||
|
||||
<!-- How long in milliseconds before full burn-in protection is achieved. -->
|
||||
<integer name="config_dreamOverlayMillisUntilFullJitter">240000</integer>
|
||||
</resources>
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.dreams;
|
||||
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.MathUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@@ -56,9 +57,15 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
|
||||
// The interval in milliseconds between burn-in protection updates.
|
||||
private final long mBurnInProtectionUpdateInterval;
|
||||
|
||||
// Amount of time in milliseconds to linear interpolate toward the final jitter offset. Once
|
||||
// this time is achieved, the normal jitter algorithm applies in full.
|
||||
private final long mMillisUntilFullJitter;
|
||||
|
||||
// Main thread handler used to schedule periodic tasks (e.g. burn-in protection updates).
|
||||
private final Handler mHandler;
|
||||
|
||||
private long mJitterStartTimeMillis;
|
||||
|
||||
@Inject
|
||||
public DreamOverlayContainerViewController(
|
||||
DreamOverlayContainerView containerView,
|
||||
@@ -68,7 +75,8 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
|
||||
@Main Handler handler,
|
||||
@Named(DreamOverlayModule.MAX_BURN_IN_OFFSET) int maxBurnInOffset,
|
||||
@Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
|
||||
burnInProtectionUpdateInterval) {
|
||||
burnInProtectionUpdateInterval,
|
||||
@Named(DreamOverlayModule.MILLIS_UNTIL_FULL_JITTER) long millisUntilFullJitter) {
|
||||
super(containerView);
|
||||
mDreamOverlayContentView = contentView;
|
||||
mStatusBarViewController = statusBarViewController;
|
||||
@@ -86,6 +94,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
|
||||
mHandler = handler;
|
||||
mMaxBurnInOffset = maxBurnInOffset;
|
||||
mBurnInProtectionUpdateInterval = burnInProtectionUpdateInterval;
|
||||
mMillisUntilFullJitter = millisUntilFullJitter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,6 +105,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
|
||||
|
||||
@Override
|
||||
protected void onViewAttached() {
|
||||
mJitterStartTimeMillis = System.currentTimeMillis();
|
||||
mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
|
||||
}
|
||||
|
||||
@@ -114,13 +124,24 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
|
||||
}
|
||||
|
||||
private void updateBurnInOffsets() {
|
||||
int burnInOffset = mMaxBurnInOffset;
|
||||
|
||||
// Make sure the offset starts at zero, to avoid a big jump in the overlay when it first
|
||||
// appears.
|
||||
long millisSinceStart = System.currentTimeMillis() - mJitterStartTimeMillis;
|
||||
if (millisSinceStart < mMillisUntilFullJitter) {
|
||||
float lerpAmount = (float) millisSinceStart / (float) mMillisUntilFullJitter;
|
||||
burnInOffset = Math.round(MathUtils.lerp(0f, burnInOffset, lerpAmount));
|
||||
}
|
||||
|
||||
// These translation values change slowly, and the set translation methods are idempotent,
|
||||
// so no translation occurs when the values don't change.
|
||||
mView.setTranslationX(getBurnInOffset(mMaxBurnInOffset * 2, true)
|
||||
- mMaxBurnInOffset);
|
||||
|
||||
mView.setTranslationY(getBurnInOffset(mMaxBurnInOffset * 2, false)
|
||||
- mMaxBurnInOffset);
|
||||
int burnInOffsetX = getBurnInOffset(burnInOffset * 2, true)
|
||||
- burnInOffset;
|
||||
int burnInOffsetY = getBurnInOffset(burnInOffset * 2, false)
|
||||
- burnInOffset;
|
||||
mView.setTranslationX(burnInOffsetX);
|
||||
mView.setTranslationY(burnInOffsetY);
|
||||
|
||||
mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public abstract class DreamOverlayModule {
|
||||
public static final String MAX_BURN_IN_OFFSET = "max_burn_in_offset";
|
||||
public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL =
|
||||
"burn_in_protection_update_interval";
|
||||
public static final String MILLIS_UNTIL_FULL_JITTER = "millis_until_full_jitter";
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@@ -106,6 +107,13 @@ public abstract class DreamOverlayModule {
|
||||
R.integer.config_dreamOverlayBurnInProtectionUpdateIntervalMillis);
|
||||
}
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@Named(MILLIS_UNTIL_FULL_JITTER)
|
||||
static long providesMillisUntilFullJitter(@Main Resources resources) {
|
||||
return resources.getInteger(R.integer.config_dreamOverlayMillisUntilFullJitter);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@DreamOverlayComponent.DreamOverlayScope
|
||||
static LifecycleOwner providesLifecycleOwner(Lazy<LifecycleRegistry> lifecycleRegistryLazy) {
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.systemui.dreams;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -49,6 +48,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
|
||||
private static final int DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT = 100;
|
||||
private static final int MAX_BURN_IN_OFFSET = 20;
|
||||
private static final long BURN_IN_PROTECTION_UPDATE_INTERVAL = 10;
|
||||
private static final long MILLIS_UNTIL_FULL_JITTER = 240 * 1000;
|
||||
|
||||
@Mock
|
||||
Resources mResources;
|
||||
@@ -100,7 +100,8 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
|
||||
mDreamOverlayStatusBarViewController,
|
||||
mHandler,
|
||||
MAX_BURN_IN_OFFSET,
|
||||
BURN_IN_PROTECTION_UPDATE_INTERVAL);
|
||||
BURN_IN_PROTECTION_UPDATE_INTERVAL,
|
||||
MILLIS_UNTIL_FULL_JITTER);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -129,14 +130,14 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBurnInProtectionUpdatesPeriodically() {
|
||||
public void testBurnInProtectionOffsetsStartAtZero() {
|
||||
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||
mController.onViewAttached();
|
||||
verify(mHandler).postDelayed(
|
||||
runnableCaptor.capture(), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
|
||||
runnableCaptor.getValue().run();
|
||||
verify(mDreamOverlayContainerView).setTranslationX(anyFloat());
|
||||
verify(mDreamOverlayContainerView).setTranslationY(anyFloat());
|
||||
verify(mDreamOverlayContainerView).setTranslationX(0.f);
|
||||
verify(mDreamOverlayContainerView).setTranslationY(0.f);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user