Loading core/java/android/view/View.java +34 −60 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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) { Loading @@ -34000,7 +33975,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility); } } if (viewRootImpl.shouldCheckFrameRateCategory()) { if (sToolkitMetricsForFrameRateDecisionFlagValue) { core/java/android/view/ViewRootImpl.java +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading core/tests/coretests/src/android/view/ViewFrameRateTest.java +56 −61 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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; Loading @@ -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(); Loading @@ -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(); Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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 Loading Loading
core/java/android/view/View.java +34 −60 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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) { Loading @@ -34000,7 +33975,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility); } } if (viewRootImpl.shouldCheckFrameRateCategory()) { if (sToolkitMetricsForFrameRateDecisionFlagValue) {
core/java/android/view/ViewRootImpl.java +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
core/tests/coretests/src/android/view/ViewFrameRateTest.java +56 −61 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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; Loading @@ -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(); Loading @@ -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(); Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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 Loading