Fix the flickering on display/font size page

In framework design, framework needs to have a snapshot
when there's a config change event since redrawing window
takes some time.
Flickering problem is caused by the timing issue between the
snapshot mechinsm and local preview update.

User can observe the flickering problem if config commit()->
snapshot in framework(old screenshot) -> app update the preview
-> snapshot(old screen) fade out.

To prevent this problem, we make sure that we update the local preview
first and then we do the commit later. In this proposal, snapshot action
is able to get the new snaptshot for the new preview.

So, the core workaround is commitOnNextFrame, we ask a delay before
we submit the commit(). Note: It doesn't matter that we use
Choreographer or main thread handler since the delay time is longer
than 1 frame. Use Choreographer to let developer understand it's a
window update.

Fix: 148192402
Test: manual test
Change-Id: I9bfc5eb39e7a9ebce2fe1414d6f0a9dd470708e8
This commit is contained in:
Tsung-Mao Fang
2021-07-08 17:58:50 +08:00
parent 723ab59bc0
commit f9ff6344e4

View File

@@ -19,6 +19,8 @@ package com.android.settings.display;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.Choreographer;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -58,14 +60,35 @@ public abstract class PreviewSeekBarPreferenceFragment extends SettingsPreferenc
private View mLarger;
private View mSmaller;
private static final long MIN_COMMIT_INTERVAL_MS = 800;
private long mLastCommitTime;
private class onPreviewSeekBarChangeListener implements OnSeekBarChangeListener {
private static final long CHANGE_BY_SEEKBAR_DELAY_MS = 100;
private static final long CHANGE_BY_BUTTON_DELAY_MS = 300;
private boolean mSeekByTouch;
private boolean mIsChanged;
private long mCommitDelayMs;
private final Choreographer.FrameCallback mCommit = f -> {
commit();
mLastCommitTime = SystemClock.elapsedRealtime();
};
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (mCurrentIndex == progress) {
mIsChanged = false;
return;
}
mIsChanged = true;
setPreviewLayer(progress, false);
if (!mSeekByTouch) {
commit();
if (mSeekByTouch) {
mCommitDelayMs = CHANGE_BY_SEEKBAR_DELAY_MS;
} else {
mCommitDelayMs = CHANGE_BY_BUTTON_DELAY_MS;
commitOnNextFrame();
}
}
@@ -76,18 +99,39 @@ public abstract class PreviewSeekBarPreferenceFragment extends SettingsPreferenc
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (mPreviewPagerAdapter.isAnimating()) {
mPreviewPagerAdapter.setAnimationEndAction(() -> commit());
} else {
commit();
}
mSeekByTouch = false;
if (!mIsChanged) {
return;
}
if (mPreviewPagerAdapter.isAnimating()) {
mPreviewPagerAdapter.setAnimationEndAction(this::commitOnNextFrame);
} else {
commitOnNextFrame();
}
}
private void commitOnNextFrame() {
if (SystemClock.elapsedRealtime() - mLastCommitTime < MIN_COMMIT_INTERVAL_MS) {
mCommitDelayMs += MIN_COMMIT_INTERVAL_MS;
}
final Choreographer choreographer = Choreographer.getInstance();
choreographer.removeFrameCallback(mCommit);
choreographer.postFrameCallbackDelayed(mCommit, mCommitDelayMs);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putLong("mLastCommitTime", mLastCommitTime);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (savedInstanceState != null) {
mLastCommitTime = savedInstanceState.getLong("mLastCommitTime");
}
final View root = super.onCreateView(inflater, container, savedInstanceState);
final ViewGroup listContainer = root.findViewById(android.R.id.list_container);
listContainer.removeAllViews();