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

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

Merge "[VRR] Vote for High_Hint when the position or the size of a View is changed" into main

parents 166b56c6 1f921f04
Loading
Loading
Loading
Loading
+34 −60
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.os.Trace.TRACE_TAG_VIEW;
import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT;
import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
@@ -19638,7 +19639,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    public final void setLeft(int left) {
        if (left != mLeft) {
            mPrivateFlags4 |= PFLAG4_HAS_MOVED;
            final boolean matrixIsIdentity = hasIdentityMatrix();
            if (matrixIsIdentity) {
                if (mAttachInfo != null) {
@@ -25592,6 +25592,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                        ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
                mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_LARGE;
            }
            mPrivateFlags4 |= PFLAG4_HAS_MOVED;
        }
        onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
@@ -33905,8 +33906,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * @hide
     */
    protected int calculateFrameRateCategory() {
        ViewRootImpl viewRootImpl = getViewRootImpl();
        ViewParent parent = mParent;
        boolean isInputMethodWindowType =
                viewRootImpl.mWindowAttributes.type == TYPE_INPUT_METHOD;
        // boost frame rate when the position or the size changed.
        if (((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == (
                PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft
                || mLastFrameTop != mTop)
                && viewRootImpl.shouldCheckFrameRateCategory()
                && parent instanceof View
                && ((View) parent).mFrameContentVelocity <= 0
                && !isInputMethodWindowType) {
            return FRAME_RATE_CATEGORY_HIGH_HINT | FRAME_RATE_CATEGORY_REASON_BOOST;
        }
        int category;
        switch (getViewRootImpl().intermittentUpdateState()) {
        switch (viewRootImpl.intermittentUpdateState()) {
            case ViewRootImpl.INTERMITTENT_STATE_INTERMITTENT -> {
                if (!sToolkitFrameRateBySizeReadOnlyFlagValue) {
                    category = FRAME_RATE_CATEGORY_NORMAL;
@@ -33940,55 +33957,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
        float velocity = mFrameContentVelocity;
        final float frameRate = mPreferredFrameRate;
        ViewParent parent = mParent;
        boolean isInputMethodWindowType = false;
        if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) {
            isInputMethodWindowType =
                    mAttachInfo.mViewRootImpl.mWindowAttributes.type == TYPE_INPUT_METHOD;
        }
        if (velocity <= 0 && Float.isNaN(frameRate)) {
            // The most common case is when nothing is set, so this special case is called
            // often.
            if (mAttachInfo.mViewVelocityApi
                    && ((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == (
                    PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft
                    || mLastFrameTop != mTop)
                    && viewRootImpl.shouldCheckFrameRate(false)
                    && parent instanceof View
                    && ((View) parent).mFrameContentVelocity <= 0
                    && !isInputMethodWindowType) {
                viewRootImpl.votePreferredFrameRate(MAX_FRAME_RATE, FRAME_RATE_COMPATIBILITY_GTE);
            }
            if (viewRootImpl.shouldCheckFrameRateCategory()) {
                int frameRateCategory = calculateFrameRateCategory();
                int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK;
                int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK;
                viewRootImpl.votePreferredFrameRateCategory(category, reason, this);
                mLastFrameRateCategory = frameRateCategory;
            }
            mLastFrameLeft = mLeft;
            mLastFrameTop = mTop;
            return;
        }
        if (viewRootImpl.shouldCheckFrameRate(frameRate > 0f)) {
        if (viewRootImpl.shouldCheckFrameRate(frameRate > 0f)
                && (frameRate > 0 || (mAttachInfo.mViewVelocityApi && velocity > 0f))) {
            float velocityFrameRate = 0f;
            if (mAttachInfo.mViewVelocityApi) {
                if (velocity < 0f
                        && ((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == (
                        PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft
                        || mLastFrameTop != mTop)
                        && mParent instanceof View
                        && ((View) mParent).mFrameContentVelocity <= 0
                        && !isInputMethodWindowType
                ) {
                    // This current calculation is very simple. If something on the screen
                    // moved, then it votes for the highest velocity.
                    velocityFrameRate = MAX_FRAME_RATE;
                } else if (velocity > 0f) {
            if (mAttachInfo.mViewVelocityApi && velocity > 0f) {
                velocityFrameRate = convertVelocityToFrameRate(velocity);
            }
            }
            if (velocityFrameRate > 0f || frameRate > 0f) {
            int compatibility;
            float frameRateToSet;
            if (frameRate >= velocityFrameRate) {
@@ -34000,7 +33975,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            }
            viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility);
        }
        }
        if (viewRootImpl.shouldCheckFrameRateCategory()) {
            if (sToolkitMetricsForFrameRateDecisionFlagValue) {
+2 −0
Original line number Diff line number Diff line
@@ -4424,6 +4424,8 @@ public final class ViewRootImpl implements ViewParent,
            }
            mFrameRateCategoryHighCount = mFrameRateCategoryHighCount > 0
                    ? mFrameRateCategoryHighCount - 1 : mFrameRateCategoryHighCount;
            mFrameRateCategoryHighHintCount = mFrameRateCategoryHighHintCount > 0
                    ? mFrameRateCategoryHighHintCount - 1 : mFrameRateCategoryHighHintCount;
            mFrameRateCategoryNormalCount = mFrameRateCategoryNormalCount > 0
                    ? mFrameRateCategoryNormalCount - 1 : mFrameRateCategoryNormalCount;
            mFrameRateCategoryLowCount = mFrameRateCategoryLowCount > 0
+56 −61
Original line number Diff line number Diff line
@@ -29,11 +29,9 @@ import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;
import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;
import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly;
import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;

import static junit.framework.Assert.assertEquals;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import android.annotation.NonNull;
@@ -100,9 +98,8 @@ public class ViewFrameRateTest {
    }

    @Test
    @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API,
            FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
    public void frameRateChangesWhenContentMoves() throws Throwable {
    @RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY)
    public void highHintWhenContentMoves() throws Throwable {
        if (!ViewProperties.vrr_enabled().orElse(true)) {
            return;
        }
@@ -110,21 +107,15 @@ public class ViewFrameRateTest {
        mActivityRule.runOnUiThread(() -> {
            mMovingView.offsetLeftAndRight(100);
            runAfterDraw(() -> {
                if (toolkitFrameRateVelocityMappingReadOnly()) {
                    float frameRate = mViewRoot.getLastPreferredFrameRate();
                    assertTrue(frameRate > 0);
                } else {
                    assertEquals(FRAME_RATE_CATEGORY_HIGH,
                assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT,
                        mViewRoot.getLastPreferredFrameRateCategory());
                }
            });
        });
        waitForAfterDraw();
    }

    @Test
    @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API,
            FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
    @RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY)
    public void inputMethodWithContentMoves() throws Throwable {
        if (!ViewProperties.vrr_enabled().orElse(true)) {
            return;
@@ -136,6 +127,8 @@ public class ViewFrameRateTest {
        final WindowManager.LayoutParams attrs = mViewRoot.mWindowAttributes;
        attrs.type = TYPE_INPUT_METHOD;
        instrumentation.runOnMainSync(() -> {
            attrs.width = 1;
            attrs.height = 1;
            mViewRoot.setLayoutParams(attrs, false);
        });
        instrumentation.waitForIdleSync();
@@ -147,14 +140,13 @@ public class ViewFrameRateTest {
        mActivityRule.runOnUiThread(() -> {
            mMovingView.offsetLeftAndRight(100);
            runAfterDraw(() -> {
                if (toolkitFrameRateVelocityMappingReadOnly()) {
                int expected = toolkitFrameRateBySizeReadOnly()
                        ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
                float frameRate = mViewRoot.getLastPreferredFrameRate();
                // frame rate shouldn't be boost with TYPE_INPUT_METHOD window type
                assertTrue(frameRate == 0);
                } else {
                    assertEquals(FRAME_RATE_CATEGORY_HIGH,
                assertEquals(expected,
                        mViewRoot.getLastPreferredFrameRateCategory());
                }
            });
        });
        waitForAfterDraw();
@@ -177,7 +169,7 @@ public class ViewFrameRateTest {


    @Test
    @RequiresFlagsEnabled(FLAG_VIEW_VELOCITY_API)
    @RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY)
    public void highHintWhenActionMove() throws Throwable {
        if (!ViewProperties.vrr_enabled().orElse(true)) {
            return;
@@ -227,62 +219,59 @@ public class ViewFrameRateTest {
        move.setSource(InputDevice.SOURCE_TOUCHSCREEN);
        instrumentation.sendPointerSync(move);

        // We should continue to enable touch boost even when GTE compatibility is present.
        // Should continue to enable touch boost.
        mActivityRule.runOnUiThread(() -> {
            mMovingView.offsetLeftAndRight(10);
            assertTrue(mViewRoot.getIsTouchBoosting());
        });

        now = SystemClock.uptimeMillis();
        MotionEvent up = MotionEvent.obtain(
                now, // downTime
                now, // eventTime
                MotionEvent.ACTION_UP, // action
                position[0], // x
                position[1], // y
                0 // metaState
        );
        up.setSource(InputDevice.SOURCE_TOUCHSCREEN);
        instrumentation.sendPointerSync(up);

        // No touch boost when there is no ongoing pressed gesture.
        mActivityRule.runOnUiThread(() -> {
            mMovingView.offsetLeftAndRight(10);
            assertFalse(mViewRoot.getIsTouchBoosting());
        });

        down.recycle();
        move.recycle();
        up.recycle();
    }

    // When the size of a View is changed, we should boost the frame rate.
    @Test
    @RequiresFlagsEnabled(FLAG_VIEW_VELOCITY_API)
    public void frameBoostDisable() throws Throwable {
    @RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY)
    public void highHintWhenSizeChanged() throws Throwable {
        if (!ViewProperties.vrr_enabled().orElse(true)) {
            return;
        }
        waitForFrameRateCategoryToSettle();
        assertEquals(FRAME_RATE_CATEGORY_LOW,
                        mViewRoot.getLastPreferredFrameRateCategory());

        int width = mMovingView.getWidth();
        int height = mMovingView.getHeight();

        ViewGroup.LayoutParams params = mMovingView.getLayoutParams();
        params.width = width * 2;
        params.height = height * 2;

        // frame rate category should be HIGH_HINT when the size is changed
        mActivityRule.runOnUiThread(() -> {
            long now = SystemClock.uptimeMillis();
            MotionEvent down = MotionEvent.obtain(
                    /* downTime */ now,
                    /* eventTime */ now,
                    /* action */ MotionEvent.ACTION_DOWN,
                    /* x */ 0f,
                    /* y */ 0f,
                    /* metaState */ 0
            );
            mActivity.dispatchTouchEvent(down);
            mMovingView.offsetLeftAndRight(10);
            mMovingView.setLayoutParams(params);
            runAfterDraw(() -> {
                assertTrue(mMovingView.getWidth() > width);
                assertTrue(mMovingView.getHeight() > height);
                assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT,
                        mViewRoot.getLastPreferredFrameRateCategory());
            });
        mActivityRule.runOnUiThread(() -> {
            mMovingView.invalidate();
        });
        waitForAfterDraw();

        // set it back to the original size
        params.width = width;
        params.height = height;
        mActivityRule.runOnUiThread(() -> {
            assertFalse(mViewRoot.getIsTouchBoosting());
            assertFalse(mViewRoot.getIsFrameRateBoosting());
            mMovingView.setLayoutParams(params);
            runAfterDraw(() -> {
                assertEquals(width, mMovingView.getWidth());
                assertEquals(height, mMovingView.getHeight());
                assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT,
                        mViewRoot.getLastPreferredFrameRateCategory());
            });
        });
        waitForAfterDraw();
    }

    @Test
@@ -804,6 +793,12 @@ public class ViewFrameRateTest {
        down.setSource(InputDevice.SOURCE_TOUCHSCREEN);
        instrumentation.sendPointerSync(down);
        assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT, mViewRoot.getLastPreferredFrameRateCategory());

        // Should still be boost with position changed
        mActivityRule.runOnUiThread(() -> {
            mMovingView.offsetLeftAndRight(10);
            assertTrue(mViewRoot.getIsTouchBoosting());
        });
    }

    @LargeTest