summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/View.java94
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/tests/coretests/src/android/view/ViewFrameRateTest.java117
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