diff options
| -rw-r--r-- | core/java/android/view/TextureView.java | 13 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 24 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 28 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/ViewRootImplTest.java | 54 |
4 files changed, 103 insertions, 16 deletions
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 896b3f4bd5c3..124aecef1d5a 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -16,6 +16,8 @@ package android.view; +import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; + import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; @@ -883,6 +885,17 @@ public class TextureView extends View { mListener = listener; } + /** + * @hide + */ + @Override + protected int calculateFrameRateCategory(float sizePercentage) { + if (mMinusTwoFrameIntervalMillis > 15 && mMinusOneFrameIntervalMillis > 15) { + return FRAME_RATE_CATEGORY_NORMAL; + } + return super.calculateFrameRateCategory(sizePercentage); + } + @UnsupportedAppUsage private final SurfaceTexture.OnFrameAvailableListener mUpdateListener = surfaceTexture -> { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4df95bf31c3f..22d34e6f7151 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5649,9 +5649,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private int mInfrequentUpdateCount = 0; private long mLastUpdateTimeMillis = 0; - private long mMinusOneFrameIntervalMillis = 0; - private long mMinusTwoFrameIntervalMillis = 0; - private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_HIGH; + /** + * @hide + */ + protected long mMinusOneFrameIntervalMillis = 0; + /** + * @hide + */ + protected long mMinusTwoFrameIntervalMillis = 0; + private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN; @@ -33612,7 +33618,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return (float) viewSize / screenSize; } - private int calculateFrameRateCategory(float sizePercentage) { + /** + * Used to calculate the frame rate category of a View. + * + * @hide + */ + protected int calculateFrameRateCategory(float sizePercentage) { if (mMinusTwoFrameIntervalMillis + mMinusOneFrameIntervalMillis < INFREQUENT_UPDATE_INTERVAL_MILLIS) { if (sizePercentage <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD) { @@ -33746,7 +33757,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis; mMinusOneFrameIntervalMillis = timeIntervalMillis; - mLastUpdateTimeMillis = currentTimeMillis; + if (mMinusOneFrameIntervalMillis - mMinusTwoFrameIntervalMillis >= 30 + && timeIntervalMillis < 2) { + return; + } if (timeIntervalMillis >= INFREQUENT_UPDATE_INTERVAL_MILLIS) { mInfrequentUpdateCount = mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS ? mInfrequentUpdateCount : mInfrequentUpdateCount + 1; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3c7c82f4268f..b5f3b9a8fa2d 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1043,7 +1043,7 @@ public final class ViewRootImpl implements ViewParent, // time for checking idle status periodically. private static final int FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS = 500; // time for revaluating the idle status before lowering the frame rate. - private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 500; + private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 1000; // time for evaluating the interval between current time and // the time when frame rate was set previously. private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100; @@ -6540,6 +6540,7 @@ public final class ViewRootImpl implements ViewParent, mHasInvalidation = false; mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, FRAME_RATE_IDLENESS_REEVALUATE_TIME); + mHasIdledMessage = true; } break; case MSG_REFRESH_POINTER_ICON: @@ -12368,14 +12369,6 @@ public final class ViewRootImpl implements ViewParent, } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } - - if (mPreferredFrameRateCategory != FRAME_RATE_CATEGORY_NO_PREFERENCE && !mHasIdledMessage) { - // Check where the display is idled periodically. - // If so, set the frame rate category to NO_PREFERENCE - mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, - FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS); - mHasIdledMessage = true; - } } private void setPreferredFrameRate(float preferredFrameRate) { @@ -12389,7 +12382,8 @@ public final class ViewRootImpl implements ViewParent, if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.traceBegin( Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate " - + preferredFrameRate); + + preferredFrameRate + " compatibility " + + mFrameRateCompatibility); } mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate, mFrameRateCompatibility).applyAsyncUnsafe(); @@ -12415,7 +12409,7 @@ public final class ViewRootImpl implements ViewParent, private boolean shouldSetFrameRate() { // use toolkitSetFrameRate flag to gate the change - return mSurface.isValid() && mPreferredFrameRate > 0 + return mSurface.isValid() && mPreferredFrameRate >= 0 && shouldEnableDvrr() && !mIsFrameRateConflicted; } @@ -12456,6 +12450,7 @@ public final class ViewRootImpl implements ViewParent, mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW; } mHasInvalidation = true; + checkIdleness(); } /** @@ -12498,6 +12493,7 @@ public final class ViewRootImpl implements ViewParent, mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING, FRAME_RATE_SETTING_REEVALUATE_TIME); } + checkIdleness(); } /** @@ -12603,4 +12599,14 @@ public final class ViewRootImpl implements ViewParent, private boolean shouldEnableDvrr() { return sToolkitSetFrameRateReadOnlyFlagValue && mIsFrameRatePowerSavingsBalanced; } + + private void checkIdleness() { + if (!mHasIdledMessage) { + // Check where the display is idled periodically. + // If so, set the frame rate category to NO_PREFERENCE + mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, + FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS); + mHasIdledMessage = true; + } + } } diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index 64cbe7f1b079..7c58de67ded6 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -1017,6 +1017,60 @@ public class ViewRootImplTest { assertEquals(viewRootImpl.isFrameRatePowerSavingsBalanced(), true); } + /** + * Test the TextureView heuristic: + * 1. Store the last 3 invalidates time - FT1, FT2, FT3. + * 2. If FT2-FT1 > 15ms && FT3-FT2 > 15ms -> vote for NORMAL category + */ + @Test + @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) + public void votePreferredFrameRate_applyTextureViewHeuristic() throws InterruptedException { + final long delay = 30L; + + TextureView view = new TextureView(sContext); + WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY); + wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check + + sInstrumentation.runOnMainSync(() -> { + WindowManager wm = sContext.getSystemService(WindowManager.class); + Display display = wm.getDefaultDisplay(); + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + wmlp.width = (int) (metrics.widthPixels * 0.9); + wmlp.height = (int) (metrics.heightPixels * 0.9); + wm.addView(view, wmlp); + }); + sInstrumentation.waitForIdleSync(); + + ViewRootImpl viewRootImpl = view.getViewRootImpl(); + + sInstrumentation.runOnMainSync(() -> { + assertEquals(viewRootImpl.getPreferredFrameRateCategory(), + FRAME_RATE_CATEGORY_NO_PREFERENCE); + view.invalidate(); + assertEquals(viewRootImpl.getPreferredFrameRateCategory(), + FRAME_RATE_CATEGORY_HIGH); + }); + + // reset the frame rate category counts + for (int i = 0; i < 5; i++) { + Thread.sleep(delay); + sInstrumentation.runOnMainSync(() -> { + view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); + view.invalidate(); + }); + sInstrumentation.waitForIdleSync(); + } + + Thread.sleep(delay); + sInstrumentation.runOnMainSync(() -> { + view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); + view.invalidate(); + assertEquals(viewRootImpl.getPreferredFrameRateCategory(), + FRAME_RATE_CATEGORY_NORMAL); + }); + } + @Test public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() { mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); |