diff options
| -rw-r--r-- | core/java/android/view/View.java | 94 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 2 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/ViewFrameRateTest.java | 117 |
3 files changed, 92 insertions, 121 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f77e21935f05..88d7a834ff53 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -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,66 +33957,23 @@ 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) { - velocityFrameRate = convertVelocityToFrameRate(velocity); - } - } - if (velocityFrameRate > 0f || frameRate > 0f) { - int compatibility; - float frameRateToSet; - if (frameRate >= velocityFrameRate) { - compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; - frameRateToSet = frameRate; - } else { - compatibility = FRAME_RATE_COMPATIBILITY_GTE; - frameRateToSet = velocityFrameRate; - } - viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility); + if (mAttachInfo.mViewVelocityApi && velocity > 0f) { + velocityFrameRate = convertVelocityToFrameRate(velocity); + } + int compatibility; + float frameRateToSet; + if (frameRate >= velocityFrameRate) { + compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; + frameRateToSet = frameRate; + } else { + compatibility = FRAME_RATE_COMPATIBILITY_GTE; + frameRateToSet = velocityFrameRate; } + viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility); } if (viewRootImpl.shouldCheckFrameRateCategory()) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 07cbaa9c905f..d224217de4b7 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -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 diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java index c01b51dcade8..b68ff78107ca 100644 --- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java +++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java @@ -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, - mViewRoot.getLastPreferredFrameRateCategory()); - } + 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()) { - 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, - mViewRoot.getLastPreferredFrameRateCategory()); - } + 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); + 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); - }); - mActivityRule.runOnUiThread(() -> { - mMovingView.invalidate(); + mMovingView.setLayoutParams(params); + runAfterDraw(() -> { + assertTrue(mMovingView.getWidth() > width); + assertTrue(mMovingView.getHeight() > height); + assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT, + mViewRoot.getLastPreferredFrameRateCategory()); + }); }); + 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 |