Loading core/java/android/view/View.java +96 −62 Original line number Diff line number Diff line Loading @@ -2431,6 +2431,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ protected static boolean sToolkitSetFrameRateReadOnlyFlagValue; private static boolean sToolkitMetricsForFrameRateDecisionFlagValue; private static final boolean sToolkitFrameRateDefaultNormalReadOnlyFlagValue = toolkitFrameRateDefaultNormalReadOnly(); private static final boolean sToolkitFrameRateBySizeReadOnlyFlagValue = toolkitFrameRateBySizeReadOnly(); // Used to set frame rate compatibility. @Surface.FrameRateCompatibility int mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; Loading Loading @@ -3764,6 +3769,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 1 PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT * 11 PFLAG4_CONTENT_SENSITIVITY_MASK * 1 PFLAG4_IS_COUNTED_AS_SENSITIVE * 1 PFLAG4_HAS_DRAWN * 1 PFLAG4_HAS_MOVED * |-------|-------|-------|-------| */ Loading Loading @@ -3896,6 +3903,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see AttachInfo#mSensitiveViewsCount */ private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000; /** * Whether this view has been drawn once with updateDisplayListIfDirty() or not. * Used by VRR to for quick detection of scrolling. */ private static final int PFLAG4_HAS_DRAWN = 0x8000000; /** * Whether this view has been moved with either setTranslationX/Y or setLeft/Top. * Used by VRR to for quick detection of scrolling. */ private static final int PFLAG4_HAS_MOVED = 0x10000000; /* End of masks for mPrivateFlags4 */ /** @hide */ Loading Loading @@ -5695,12 +5715,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private ViewTranslationResponse mViewTranslationResponse; /** * The multiplier for mAttachInfo.mSmallSizePixels to consider a View to be small * if both dimensions are smaller than this. * The size in DP that is considered small for VRR purposes, if square. */ private static final float FRAME_RATE_SQUARE_SMALL_SIZE_DP = 40f; /** * The size in DP that is considered small for VRR purposes in the narrow dimension. Used for * narrow Views like a progress bar. */ private static final int FRAME_RATE_SQUARE_SMALL_SIZE_MULTIPLIER = 4; private static final float FRAME_RATE_NARROW_SIZE_DP = 10f; private static final long INFREQUENT_UPDATE_INTERVAL_MILLIS = 100; private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100; private static final int INFREQUENT_UPDATE_COUNTS = 2; // The preferred frame rate of the view that is mainly used for Loading @@ -5712,16 +5737,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * @hide */ protected long mMinusOneFrameIntervalMillis = 0; protected int mMinusOneFrameIntervalMillis = 0; /** * @hide */ protected long mMinusTwoFrameIntervalMillis = 0; protected int mMinusTwoFrameIntervalMillis = 0; private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; private float mLastFrameX = Float.NaN; private float mLastFrameY = Float.NaN; @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN; @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) Loading Loading @@ -19420,6 +19442,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public final void setTop(int top) { if (top != mTop) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (mAttachInfo != null) { Loading Loading @@ -19544,6 +19567,7 @@ 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 @@ -19800,6 +19824,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @RemotableViewMethod public void setTranslationX(float translationX) { if (translationX != getTranslationX()) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; invalidateViewProperty(true, false); mRenderNode.setTranslationX(translationX); invalidateViewProperty(false, true); Loading Loading @@ -19836,6 +19861,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @RemotableViewMethod public void setTranslationY(float translationY) { if (translationY != getTranslationY()) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; invalidateViewProperty(true, false); mRenderNode.setTranslationY(translationY); invalidateViewProperty(false, true); Loading Loading @@ -20308,6 +20334,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void offsetTopAndBottom(int offset) { if (offset != 0) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (isHardwareAccelerated()) { Loading Loading @@ -20359,6 +20386,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void offsetLeftAndRight(int offset) { if (offset != 0) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (isHardwareAccelerated()) { Loading Loading @@ -20758,7 +20786,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // For VRR to vote the preferred frame rate if (sToolkitSetFrameRateReadOnlyFlagValue) { updateInfrequentCount(); votePreferredFrameRate(); } Loading Loading @@ -20866,7 +20893,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mParent != null && mAttachInfo != null) { // For VRR to vote the preferred frame rate if (sToolkitSetFrameRateReadOnlyFlagValue) { updateInfrequentCount(); votePreferredFrameRate(); } mParent.onDescendantInvalidated(this, this); Loading Loading @@ -23556,8 +23582,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return renderNode; } mLastFrameX = mLeft + mRenderNode.getTranslationX(); mLastFrameY = mTop + mRenderNode.getTranslationY(); mPrivateFlags4 = (mPrivateFlags4 & ~PFLAG4_HAS_MOVED) | PFLAG4_HAS_DRAWN; if (sToolkitSetFrameRateReadOnlyFlagValue) { updateInfrequentCount(); } if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || !renderNode.hasDisplayList() Loading Loading @@ -25398,6 +25426,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; changed = true; // Remember our drawn bit Loading Loading @@ -25471,15 +25500,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { if (mAttachInfo != null) { int narrowSize = mAttachInfo.mSmallSizePixels; int smallSize = narrowSize * FRAME_RATE_SQUARE_SMALL_SIZE_MULTIPLIER; float density = mAttachInfo.mDensity; int narrowSize = (int) (density * FRAME_RATE_NARROW_SIZE_DP); int smallSize = (int) (density * FRAME_RATE_SQUARE_SMALL_SIZE_DP); if (newWidth <= narrowSize || newHeight <= narrowSize || (newWidth <= smallSize && newHeight <= smallSize)) { int category = toolkitFrameRateBySizeReadOnly() int category = sToolkitFrameRateBySizeReadOnlyFlagValue ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL; mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_SMALL; } else { int category = toolkitFrameRateDefaultNormalReadOnly() int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_LARGE; } Loading Loading @@ -32051,11 +32081,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int mSensitiveViewsCount; /** * The size used for a View to be considered small for the purposes of using * low refresh rate by default. This is the size in one direction, so a long, thin * item like a progress bar can be compared to this. * The value of viewVelocityApi(), read only once per ViewRootImpl */ final boolean mViewVelocityApi = viewVelocityApi(); /** * Density so that it doesn't need to be retrieved on every invalidation. */ final int mSmallSizePixels; final float mDensity; /** * Creates a new set of attachment information with the specified Loading @@ -32074,7 +32107,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mHandler = handler; mRootCallbacks = effectPlayer; mTreeObserver = new ViewTreeObserver(context); mSmallSizePixels = (int) (context.getResources().getDisplayMetrics().density * 10); mDensity = context.getResources().getDisplayMetrics().density; } void increaseSensitiveViewsCount() { Loading Loading @@ -33821,17 +33854,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int width = mRight - mLeft; int height = mBottom - mTop; if (viewRootImpl != null && (width != 0 && height != 0)) { if (viewVelocityApi()) { if (mAttachInfo.mViewVelocityApi) { float velocity = mFrameContentVelocity; if (velocity < 0f) { int mask = PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN; if (velocity < 0f && (mPrivateFlags4 & mask) == mask) { // This current calculation is very simple. If something on the screen moved, // then it votes for the highest velocity. If it doesn't move, then return 0. RenderNode renderNode = mRenderNode; float x = mLeft + renderNode.getTranslationX(); float y = mTop + renderNode.getTranslationY(); velocity = (!Float.isNaN(mLastFrameX) && (x != mLastFrameX || y != mLastFrameY)) ? 100_000f : 0f; velocity = Float.POSITIVE_INFINITY; } if (velocity > 0f) { float frameRate = convertVelocityToFrameRate(velocity); Loading @@ -33849,25 +33878,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (Float.isNaN(mPreferredFrameRate)) { frameRateCategory = calculateFrameRateCategory(); } else if (mPreferredFrameRate < 0) { if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE) { switch ((int) mPreferredFrameRate) { case (int) REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE -> frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE | FRAME_RATE_CATEGORY_REASON_REQUESTED; } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_LOW) { case (int) REQUESTED_FRAME_RATE_CATEGORY_LOW -> frameRateCategory = FRAME_RATE_CATEGORY_LOW | FRAME_RATE_CATEGORY_REASON_REQUESTED; } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_NORMAL) { case (int) REQUESTED_FRAME_RATE_CATEGORY_NORMAL -> frameRateCategory = FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_REQUESTED; } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_HIGH) { case (int) REQUESTED_FRAME_RATE_CATEGORY_HIGH -> frameRateCategory = FRAME_RATE_CATEGORY_HIGH | FRAME_RATE_CATEGORY_REASON_REQUESTED; } else { default -> { // invalid frame rate, use default int category = toolkitFrameRateDefaultNormalReadOnly() int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; frameRateCategory = category | FRAME_RATE_CATEGORY_REASON_INVALID; } } } else { viewRootImpl.votePreferredFrameRate(mPreferredFrameRate, mFrameRateCompatibility); Loading @@ -33883,7 +33914,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } private float convertVelocityToFrameRate(float velocityPps) { float density = getResources().getDisplayMetrics().density; float density = mAttachInfo.mDensity; float velocityDps = velocityPps / density; // Choose a frame rate in increments of 10fps return Math.min(140f, 60f + (10f * (float) Math.floor(velocityDps / 300f))); Loading Loading @@ -33971,8 +34002,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * - otherwise, use the previous category value. */ private void updateInfrequentCount() { if (!willNotDraw()) { long currentTimeMillis = getDrawingTime(); long timeIntervalMillis = currentTimeMillis - mLastUpdateTimeMillis; int timeIntervalMillis = (int) Math.min(Integer.MAX_VALUE, currentTimeMillis - mLastUpdateTimeMillis); mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis; mMinusOneFrameIntervalMillis = timeIntervalMillis; Loading @@ -33988,3 +34021,4 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } } } core/java/android/view/ViewRootImpl.java +8 −8 Original line number Diff line number Diff line Loading @@ -12632,14 +12632,14 @@ public final class ViewRootImpl implements ViewParent, */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) public void votePreferredFrameRateCategory(int frameRateCategory, int reason, View view) { if (frameRateCategory == FRAME_RATE_CATEGORY_HIGH) { mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; } else if (frameRateCategory == FRAME_RATE_CATEGORY_HIGH_HINT) { mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT; } else if (frameRateCategory == FRAME_RATE_CATEGORY_NORMAL) { switch (frameRateCategory) { case FRAME_RATE_CATEGORY_LOW -> mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT; case FRAME_RATE_CATEGORY_NORMAL -> mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT; } else if (frameRateCategory == FRAME_RATE_CATEGORY_LOW) { mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT; case FRAME_RATE_CATEGORY_HIGH_HINT -> mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT; case FRAME_RATE_CATEGORY_HIGH -> mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; } int oldCategory = mPreferredFrameRateCategory; core/tests/coretests/src/android/view/ViewFrameRateTest.java +6 −6 Original line number Diff line number Diff line Loading @@ -176,8 +176,8 @@ public class ViewFrameRateTest { mActivityRule.runOnUiThread(() -> { float density = mActivity.getResources().getDisplayMetrics().density; ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams(); layoutParams.height = 4 * ((int) (10 * density)); layoutParams.width = 4 * ((int) (10 * density)); layoutParams.height = ((int) (40 * density)); layoutParams.width = ((int) (40 * density)); mMovingView.setLayoutParams(layoutParams); mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch1::countDown); }); Loading Loading @@ -251,8 +251,8 @@ public class ViewFrameRateTest { mActivityRule.runOnUiThread(() -> { float density = mActivity.getResources().getDisplayMetrics().density; ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams(); layoutParams.height = 4 * ((int) (10 * density)); layoutParams.width = 4 * ((int) Math.ceil(10 * density)) + 1; layoutParams.height = (int) (40 * density); layoutParams.width = ((int) Math.ceil(40 * density)) + 1; mMovingView.setLayoutParams(layoutParams); mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch1::countDown); }); Loading @@ -276,8 +276,8 @@ public class ViewFrameRateTest { mActivityRule.runOnUiThread(() -> { float density = mActivity.getResources().getDisplayMetrics().density; ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams(); layoutParams.height = 4 * ((int) Math.ceil(10 * density)) + 1; layoutParams.width = 4 * ((int) (10 * density)); layoutParams.height = ((int) Math.ceil(40 * density)) + 1; layoutParams.width = ((int) (40 * density)); mMovingView.setLayoutParams(layoutParams); mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch1::countDown); }); Loading Loading
core/java/android/view/View.java +96 −62 Original line number Diff line number Diff line Loading @@ -2431,6 +2431,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ protected static boolean sToolkitSetFrameRateReadOnlyFlagValue; private static boolean sToolkitMetricsForFrameRateDecisionFlagValue; private static final boolean sToolkitFrameRateDefaultNormalReadOnlyFlagValue = toolkitFrameRateDefaultNormalReadOnly(); private static final boolean sToolkitFrameRateBySizeReadOnlyFlagValue = toolkitFrameRateBySizeReadOnly(); // Used to set frame rate compatibility. @Surface.FrameRateCompatibility int mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; Loading Loading @@ -3764,6 +3769,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 1 PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT * 11 PFLAG4_CONTENT_SENSITIVITY_MASK * 1 PFLAG4_IS_COUNTED_AS_SENSITIVE * 1 PFLAG4_HAS_DRAWN * 1 PFLAG4_HAS_MOVED * |-------|-------|-------|-------| */ Loading Loading @@ -3896,6 +3903,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see AttachInfo#mSensitiveViewsCount */ private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000; /** * Whether this view has been drawn once with updateDisplayListIfDirty() or not. * Used by VRR to for quick detection of scrolling. */ private static final int PFLAG4_HAS_DRAWN = 0x8000000; /** * Whether this view has been moved with either setTranslationX/Y or setLeft/Top. * Used by VRR to for quick detection of scrolling. */ private static final int PFLAG4_HAS_MOVED = 0x10000000; /* End of masks for mPrivateFlags4 */ /** @hide */ Loading Loading @@ -5695,12 +5715,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private ViewTranslationResponse mViewTranslationResponse; /** * The multiplier for mAttachInfo.mSmallSizePixels to consider a View to be small * if both dimensions are smaller than this. * The size in DP that is considered small for VRR purposes, if square. */ private static final float FRAME_RATE_SQUARE_SMALL_SIZE_DP = 40f; /** * The size in DP that is considered small for VRR purposes in the narrow dimension. Used for * narrow Views like a progress bar. */ private static final int FRAME_RATE_SQUARE_SMALL_SIZE_MULTIPLIER = 4; private static final float FRAME_RATE_NARROW_SIZE_DP = 10f; private static final long INFREQUENT_UPDATE_INTERVAL_MILLIS = 100; private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100; private static final int INFREQUENT_UPDATE_COUNTS = 2; // The preferred frame rate of the view that is mainly used for Loading @@ -5712,16 +5737,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * @hide */ protected long mMinusOneFrameIntervalMillis = 0; protected int mMinusOneFrameIntervalMillis = 0; /** * @hide */ protected long mMinusTwoFrameIntervalMillis = 0; protected int mMinusTwoFrameIntervalMillis = 0; private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; private float mLastFrameX = Float.NaN; private float mLastFrameY = Float.NaN; @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN; @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) Loading Loading @@ -19420,6 +19442,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public final void setTop(int top) { if (top != mTop) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (mAttachInfo != null) { Loading Loading @@ -19544,6 +19567,7 @@ 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 @@ -19800,6 +19824,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @RemotableViewMethod public void setTranslationX(float translationX) { if (translationX != getTranslationX()) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; invalidateViewProperty(true, false); mRenderNode.setTranslationX(translationX); invalidateViewProperty(false, true); Loading Loading @@ -19836,6 +19861,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @RemotableViewMethod public void setTranslationY(float translationY) { if (translationY != getTranslationY()) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; invalidateViewProperty(true, false); mRenderNode.setTranslationY(translationY); invalidateViewProperty(false, true); Loading Loading @@ -20308,6 +20334,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void offsetTopAndBottom(int offset) { if (offset != 0) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (isHardwareAccelerated()) { Loading Loading @@ -20359,6 +20386,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void offsetLeftAndRight(int offset) { if (offset != 0) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (isHardwareAccelerated()) { Loading Loading @@ -20758,7 +20786,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // For VRR to vote the preferred frame rate if (sToolkitSetFrameRateReadOnlyFlagValue) { updateInfrequentCount(); votePreferredFrameRate(); } Loading Loading @@ -20866,7 +20893,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mParent != null && mAttachInfo != null) { // For VRR to vote the preferred frame rate if (sToolkitSetFrameRateReadOnlyFlagValue) { updateInfrequentCount(); votePreferredFrameRate(); } mParent.onDescendantInvalidated(this, this); Loading Loading @@ -23556,8 +23582,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return renderNode; } mLastFrameX = mLeft + mRenderNode.getTranslationX(); mLastFrameY = mTop + mRenderNode.getTranslationY(); mPrivateFlags4 = (mPrivateFlags4 & ~PFLAG4_HAS_MOVED) | PFLAG4_HAS_DRAWN; if (sToolkitSetFrameRateReadOnlyFlagValue) { updateInfrequentCount(); } if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || !renderNode.hasDisplayList() Loading Loading @@ -25398,6 +25426,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; changed = true; // Remember our drawn bit Loading Loading @@ -25471,15 +25500,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { if (mAttachInfo != null) { int narrowSize = mAttachInfo.mSmallSizePixels; int smallSize = narrowSize * FRAME_RATE_SQUARE_SMALL_SIZE_MULTIPLIER; float density = mAttachInfo.mDensity; int narrowSize = (int) (density * FRAME_RATE_NARROW_SIZE_DP); int smallSize = (int) (density * FRAME_RATE_SQUARE_SMALL_SIZE_DP); if (newWidth <= narrowSize || newHeight <= narrowSize || (newWidth <= smallSize && newHeight <= smallSize)) { int category = toolkitFrameRateBySizeReadOnly() int category = sToolkitFrameRateBySizeReadOnlyFlagValue ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL; mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_SMALL; } else { int category = toolkitFrameRateDefaultNormalReadOnly() int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_LARGE; } Loading Loading @@ -32051,11 +32081,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int mSensitiveViewsCount; /** * The size used for a View to be considered small for the purposes of using * low refresh rate by default. This is the size in one direction, so a long, thin * item like a progress bar can be compared to this. * The value of viewVelocityApi(), read only once per ViewRootImpl */ final boolean mViewVelocityApi = viewVelocityApi(); /** * Density so that it doesn't need to be retrieved on every invalidation. */ final int mSmallSizePixels; final float mDensity; /** * Creates a new set of attachment information with the specified Loading @@ -32074,7 +32107,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mHandler = handler; mRootCallbacks = effectPlayer; mTreeObserver = new ViewTreeObserver(context); mSmallSizePixels = (int) (context.getResources().getDisplayMetrics().density * 10); mDensity = context.getResources().getDisplayMetrics().density; } void increaseSensitiveViewsCount() { Loading Loading @@ -33821,17 +33854,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int width = mRight - mLeft; int height = mBottom - mTop; if (viewRootImpl != null && (width != 0 && height != 0)) { if (viewVelocityApi()) { if (mAttachInfo.mViewVelocityApi) { float velocity = mFrameContentVelocity; if (velocity < 0f) { int mask = PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN; if (velocity < 0f && (mPrivateFlags4 & mask) == mask) { // This current calculation is very simple. If something on the screen moved, // then it votes for the highest velocity. If it doesn't move, then return 0. RenderNode renderNode = mRenderNode; float x = mLeft + renderNode.getTranslationX(); float y = mTop + renderNode.getTranslationY(); velocity = (!Float.isNaN(mLastFrameX) && (x != mLastFrameX || y != mLastFrameY)) ? 100_000f : 0f; velocity = Float.POSITIVE_INFINITY; } if (velocity > 0f) { float frameRate = convertVelocityToFrameRate(velocity); Loading @@ -33849,25 +33878,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (Float.isNaN(mPreferredFrameRate)) { frameRateCategory = calculateFrameRateCategory(); } else if (mPreferredFrameRate < 0) { if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE) { switch ((int) mPreferredFrameRate) { case (int) REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE -> frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE | FRAME_RATE_CATEGORY_REASON_REQUESTED; } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_LOW) { case (int) REQUESTED_FRAME_RATE_CATEGORY_LOW -> frameRateCategory = FRAME_RATE_CATEGORY_LOW | FRAME_RATE_CATEGORY_REASON_REQUESTED; } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_NORMAL) { case (int) REQUESTED_FRAME_RATE_CATEGORY_NORMAL -> frameRateCategory = FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_REQUESTED; } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_HIGH) { case (int) REQUESTED_FRAME_RATE_CATEGORY_HIGH -> frameRateCategory = FRAME_RATE_CATEGORY_HIGH | FRAME_RATE_CATEGORY_REASON_REQUESTED; } else { default -> { // invalid frame rate, use default int category = toolkitFrameRateDefaultNormalReadOnly() int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; frameRateCategory = category | FRAME_RATE_CATEGORY_REASON_INVALID; } } } else { viewRootImpl.votePreferredFrameRate(mPreferredFrameRate, mFrameRateCompatibility); Loading @@ -33883,7 +33914,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } private float convertVelocityToFrameRate(float velocityPps) { float density = getResources().getDisplayMetrics().density; float density = mAttachInfo.mDensity; float velocityDps = velocityPps / density; // Choose a frame rate in increments of 10fps return Math.min(140f, 60f + (10f * (float) Math.floor(velocityDps / 300f))); Loading Loading @@ -33971,8 +34002,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * - otherwise, use the previous category value. */ private void updateInfrequentCount() { if (!willNotDraw()) { long currentTimeMillis = getDrawingTime(); long timeIntervalMillis = currentTimeMillis - mLastUpdateTimeMillis; int timeIntervalMillis = (int) Math.min(Integer.MAX_VALUE, currentTimeMillis - mLastUpdateTimeMillis); mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis; mMinusOneFrameIntervalMillis = timeIntervalMillis; Loading @@ -33988,3 +34021,4 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } } }
core/java/android/view/ViewRootImpl.java +8 −8 Original line number Diff line number Diff line Loading @@ -12632,14 +12632,14 @@ public final class ViewRootImpl implements ViewParent, */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) public void votePreferredFrameRateCategory(int frameRateCategory, int reason, View view) { if (frameRateCategory == FRAME_RATE_CATEGORY_HIGH) { mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; } else if (frameRateCategory == FRAME_RATE_CATEGORY_HIGH_HINT) { mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT; } else if (frameRateCategory == FRAME_RATE_CATEGORY_NORMAL) { switch (frameRateCategory) { case FRAME_RATE_CATEGORY_LOW -> mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT; case FRAME_RATE_CATEGORY_NORMAL -> mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT; } else if (frameRateCategory == FRAME_RATE_CATEGORY_LOW) { mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT; case FRAME_RATE_CATEGORY_HIGH_HINT -> mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT; case FRAME_RATE_CATEGORY_HIGH -> mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; } int oldCategory = mPreferredFrameRateCategory;
core/tests/coretests/src/android/view/ViewFrameRateTest.java +6 −6 Original line number Diff line number Diff line Loading @@ -176,8 +176,8 @@ public class ViewFrameRateTest { mActivityRule.runOnUiThread(() -> { float density = mActivity.getResources().getDisplayMetrics().density; ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams(); layoutParams.height = 4 * ((int) (10 * density)); layoutParams.width = 4 * ((int) (10 * density)); layoutParams.height = ((int) (40 * density)); layoutParams.width = ((int) (40 * density)); mMovingView.setLayoutParams(layoutParams); mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch1::countDown); }); Loading Loading @@ -251,8 +251,8 @@ public class ViewFrameRateTest { mActivityRule.runOnUiThread(() -> { float density = mActivity.getResources().getDisplayMetrics().density; ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams(); layoutParams.height = 4 * ((int) (10 * density)); layoutParams.width = 4 * ((int) Math.ceil(10 * density)) + 1; layoutParams.height = (int) (40 * density); layoutParams.width = ((int) Math.ceil(40 * density)) + 1; mMovingView.setLayoutParams(layoutParams); mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch1::countDown); }); Loading @@ -276,8 +276,8 @@ public class ViewFrameRateTest { mActivityRule.runOnUiThread(() -> { float density = mActivity.getResources().getDisplayMetrics().density; ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams(); layoutParams.height = 4 * ((int) Math.ceil(10 * density)) + 1; layoutParams.width = 4 * ((int) (10 * density)); layoutParams.height = ((int) Math.ceil(40 * density)) + 1; layoutParams.width = ((int) (40 * density)); mMovingView.setLayoutParams(layoutParams); mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch1::countDown); }); Loading