Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f9ff6344 authored by Tsung-Mao Fang's avatar Tsung-Mao Fang
Browse files

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
parent 723ab59b
Loading
Loading
Loading
Loading
+50 −6
Original line number Diff line number Diff line
@@ -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) {
            mSeekByTouch = false;
            if (!mIsChanged) {
                return;
            }
            if (mPreviewPagerAdapter.isAnimating()) {
                mPreviewPagerAdapter.setAnimationEndAction(() -> commit());
                mPreviewPagerAdapter.setAnimationEndAction(this::commitOnNextFrame);
            } else {
                commit();
                commitOnNextFrame();
            }
            mSeekByTouch = false;
        }

        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();