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

Commit e789895c authored by Jian-Syuan (Shane) Wong's avatar Jian-Syuan (Shane) Wong Committed by Android (Google) Code Review
Browse files

Merge "Fix frame rate idleness and TextureView video play logic" into main

parents 6a8f701e 487fc020
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.view;

import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -883,6 +885,17 @@ public class TextureView extends View {
        mListener = listener;
    }

    /**
     * @hide
     */
    @Override
    protected int calculateFrameRateCategory(float sizePercentage) {
        if (mMinusTwoFrameIntervalMillis > 15 && mMinusOneFrameIntervalMillis > 15) {
            return FRAME_RATE_CATEGORY_NORMAL;
        }
        return super.calculateFrameRateCategory(sizePercentage);
    }

    @UnsupportedAppUsage
    private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
            surfaceTexture -> {
+19 −5
Original line number Diff line number Diff line
@@ -5649,9 +5649,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    private int mInfrequentUpdateCount = 0;
    private long mLastUpdateTimeMillis = 0;
    private long mMinusOneFrameIntervalMillis = 0;
    private long mMinusTwoFrameIntervalMillis = 0;
    private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
    /**
     * @hide
     */
    protected long mMinusOneFrameIntervalMillis = 0;
    /**
     * @hide
     */
    protected long mMinusTwoFrameIntervalMillis = 0;
    private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
    @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
    public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN;
@@ -33612,7 +33618,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return (float) viewSize / screenSize;
    }
    private int calculateFrameRateCategory(float sizePercentage) {
    /**
     * Used to calculate the frame rate category of a View.
     *
     * @hide
     */
    protected int calculateFrameRateCategory(float sizePercentage) {
        if (mMinusTwoFrameIntervalMillis + mMinusOneFrameIntervalMillis
                < INFREQUENT_UPDATE_INTERVAL_MILLIS) {
            if (sizePercentage <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD) {
@@ -33746,7 +33757,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis;
        mMinusOneFrameIntervalMillis = timeIntervalMillis;
        mLastUpdateTimeMillis = currentTimeMillis;
        if (mMinusOneFrameIntervalMillis - mMinusTwoFrameIntervalMillis >= 30
                && timeIntervalMillis < 2) {
            return;
        }
        if (timeIntervalMillis >= INFREQUENT_UPDATE_INTERVAL_MILLIS) {
            mInfrequentUpdateCount = mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS
                        ? mInfrequentUpdateCount : mInfrequentUpdateCount + 1;
+17 −11
Original line number Diff line number Diff line
@@ -1043,7 +1043,7 @@ public final class ViewRootImpl implements ViewParent,
    // time for checking idle status periodically.
    private static final int FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS = 500;
    // time for revaluating the idle status before lowering the frame rate.
    private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 500;
    private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 1000;
    // time for evaluating the interval between current time and
    // the time when frame rate was set previously.
    private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100;
@@ -6540,6 +6540,7 @@ public final class ViewRootImpl implements ViewParent,
                        mHasInvalidation = false;
                        mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
                                FRAME_RATE_IDLENESS_REEVALUATE_TIME);
                        mHasIdledMessage = true;
                    }
                    break;
                case MSG_REFRESH_POINTER_ICON:
@@ -12368,14 +12369,6 @@ public final class ViewRootImpl implements ViewParent,
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        if (mPreferredFrameRateCategory != FRAME_RATE_CATEGORY_NO_PREFERENCE && !mHasIdledMessage) {
            // Check where the display is idled periodically.
            // If so, set the frame rate category to NO_PREFERENCE
            mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
                    FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS);
            mHasIdledMessage = true;
        }
    }
    private void setPreferredFrameRate(float preferredFrameRate) {
@@ -12389,7 +12382,8 @@ public final class ViewRootImpl implements ViewParent,
                if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                    Trace.traceBegin(
                            Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
                                + preferredFrameRate);
                                + preferredFrameRate + " compatibility "
                                + mFrameRateCompatibility);
                }
                mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate,
                    mFrameRateCompatibility).applyAsyncUnsafe();
@@ -12415,7 +12409,7 @@ public final class ViewRootImpl implements ViewParent,
    private boolean shouldSetFrameRate() {
        // use toolkitSetFrameRate flag to gate the change
        return mSurface.isValid() && mPreferredFrameRate > 0
        return mSurface.isValid() && mPreferredFrameRate >= 0
                && shouldEnableDvrr() && !mIsFrameRateConflicted;
    }
@@ -12456,6 +12450,7 @@ public final class ViewRootImpl implements ViewParent,
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW;
        }
        mHasInvalidation = true;
        checkIdleness();
    }
    /**
@@ -12498,6 +12493,7 @@ public final class ViewRootImpl implements ViewParent,
            mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING,
                    FRAME_RATE_SETTING_REEVALUATE_TIME);
        }
        checkIdleness();
    }
    /**
@@ -12603,4 +12599,14 @@ public final class ViewRootImpl implements ViewParent,
    private boolean shouldEnableDvrr() {
        return sToolkitSetFrameRateReadOnlyFlagValue && mIsFrameRatePowerSavingsBalanced;
    }
    private void checkIdleness() {
        if (!mHasIdledMessage) {
            // Check where the display is idled periodically.
            // If so, set the frame rate category to NO_PREFERENCE
            mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
                    FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS);
            mHasIdledMessage = true;
        }
    }
}
+54 −0
Original line number Diff line number Diff line
@@ -1017,6 +1017,60 @@ public class ViewRootImplTest {
        assertEquals(viewRootImpl.isFrameRatePowerSavingsBalanced(), true);
    }

    /**
     * Test the TextureView heuristic:
     * 1. Store the last 3 invalidates time - FT1, FT2, FT3.
     * 2. If FT2-FT1 > 15ms && FT3-FT2 > 15ms -> vote for NORMAL category
     */
    @Test
    @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
    public void votePreferredFrameRate_applyTextureViewHeuristic() throws InterruptedException {
        final long delay = 30L;

        TextureView view = new TextureView(sContext);
        WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
        wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check

        sInstrumentation.runOnMainSync(() -> {
            WindowManager wm = sContext.getSystemService(WindowManager.class);
            Display display = wm.getDefaultDisplay();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getMetrics(metrics);
            wmlp.width = (int) (metrics.widthPixels * 0.9);
            wmlp.height = (int) (metrics.heightPixels * 0.9);
            wm.addView(view, wmlp);
        });
        sInstrumentation.waitForIdleSync();

        ViewRootImpl viewRootImpl = view.getViewRootImpl();

        sInstrumentation.runOnMainSync(() -> {
            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
                    FRAME_RATE_CATEGORY_NO_PREFERENCE);
            view.invalidate();
            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
                    FRAME_RATE_CATEGORY_HIGH);
        });

         // reset the frame rate category counts
        for (int i = 0; i < 5; i++) {
            Thread.sleep(delay);
            sInstrumentation.runOnMainSync(() -> {
                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
                view.invalidate();
            });
            sInstrumentation.waitForIdleSync();
        }

        Thread.sleep(delay);
        sInstrumentation.runOnMainSync(() -> {
            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT);
            view.invalidate();
            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
                    FRAME_RATE_CATEGORY_NORMAL);
        });
    }

    @Test
    public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() {
        mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);