Loading core/java/android/view/DisplayInfo.java +4 −3 Original line number Diff line number Diff line Loading @@ -547,16 +547,17 @@ public final class DisplayInfo implements Parcelable { * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable * mode could be found. */ public int findDefaultModeByRefreshRate(float refreshRate) { @Nullable public Display.Mode findDefaultModeByRefreshRate(float refreshRate) { Display.Mode[] modes = supportedModes; Display.Mode defaultMode = getDefaultMode(); for (int i = 0; i < modes.length; i++) { if (modes[i].matches( defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) { return modes[i].getModeId(); return modes[i]; } } return 0; return null; } /** Loading core/java/android/view/Surface.java +9 −0 Original line number Diff line number Diff line Loading @@ -217,6 +217,15 @@ public class Surface implements Parcelable { */ public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; /** * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display * to operate at the exact frame rate. * * This is used internally by the platform and should not be used by apps. * @hide */ public static final int FRAME_RATE_COMPATIBILITY_EXACT = 100; /** * Create an empty surface, which will later be filled in by readFromParcel(). * @hide Loading services/core/java/com/android/server/display/DisplayManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -1357,7 +1357,7 @@ public final class DisplayManagerService extends SystemService { // Scan supported modes returned by display.getInfo() to find a mode with the same // size as the default display mode but with the specified refresh rate instead. requestedModeId = display.getDisplayInfoLocked().findDefaultModeByRefreshRate( requestedRefreshRate); requestedRefreshRate).getModeId(); } mDisplayModeDirector.getAppRequestObserver().setAppRequestedMode( displayId, requestedModeId); Loading services/core/java/com/android/server/wm/RefreshRatePolicy.java +18 −8 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ import android.view.DisplayInfo; */ class RefreshRatePolicy { private final int mLowRefreshRateId; private final Mode mLowRefreshRateMode; private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>(); private final HighRefreshRateDenylist mHighRefreshRateDenylist; private final WindowManagerService mWmService; Loading Loading @@ -56,7 +56,7 @@ class RefreshRatePolicy { RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo, HighRefreshRateDenylist denylist) { mLowRefreshRateId = findLowRefreshRateModeId(displayInfo); mLowRefreshRateMode = findLowRefreshRateMode(displayInfo); mHighRefreshRateDenylist = denylist; mWmService = wmService; } Loading @@ -65,7 +65,7 @@ class RefreshRatePolicy { * Finds the mode id with the lowest refresh rate which is >= 60hz and same resolution as the * default mode. */ private int findLowRefreshRateModeId(DisplayInfo displayInfo) { private Mode findLowRefreshRateMode(DisplayInfo displayInfo) { Mode mode = displayInfo.getDefaultMode(); float[] refreshRates = displayInfo.getDefaultRefreshRates(); float bestRefreshRate = mode.getRefreshRate(); Loading Loading @@ -104,13 +104,9 @@ class RefreshRatePolicy { // If app is using Camera, force it to default (lower) refresh rate. if (mNonHighRefreshRatePackages.contains(packageName)) { return mLowRefreshRateId; return mLowRefreshRateMode.getModeId(); } // If app is denylisted using higher refresh rate, return default (lower) refresh rate if (mHighRefreshRateDenylist.isDenylisted(packageName)) { return mLowRefreshRateId; } return 0; } Loading @@ -137,4 +133,18 @@ class RefreshRatePolicy { } return LAYER_PRIORITY_UNSET; } float getPreferredRefreshRate(WindowState w) { // If app is animating, it's not able to control refresh rate because we want the animation // to run in default refresh rate. if (w.isAnimating(TRANSITION | PARENTS)) { return 0; } final String packageName = w.getOwningPackage(); if (mHighRefreshRateDenylist.isDenylisted(packageName)) { return mLowRefreshRateMode.getRefreshRate(); } return 0; } } services/core/java/com/android/server/wm/WindowState.java +18 −3 Original line number Diff line number Diff line Loading @@ -233,6 +233,7 @@ import android.view.InputWindowHandle; import android.view.InsetsSource; import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.Surface; import android.view.Surface.Rotation; import android.view.SurfaceControl; import android.view.SurfaceSession; Loading Loading @@ -730,6 +731,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET; /** * This is the frame rate which is passed to SurfaceFlinger if the window is part of the * high refresh rate deny list. The variable is cached, so we do not send too many updates to * SF. */ float mDenyListFrameRate = 0f; static final int BLAST_TIMEOUT_DURATION = 5000; /* milliseconds */ private final WindowProcessController mWpcForDisplayAreaConfigChanges; Loading Loading @@ -5233,7 +5241,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mOwnerCanUseBackgroundBlur; } /** * Notifies SF about the priority of the window, if it changed. SF then uses this information * to decide which window's desired rendering rate should have a priority when deciding about Loading @@ -5242,13 +5249,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ @VisibleForTesting void updateFrameRateSelectionPriorityIfNeeded() { final int priority = getDisplayContent().getDisplayPolicy().getRefreshRatePolicy() .calculatePriority(this); RefreshRatePolicy refreshRatePolicy = getDisplayContent().getDisplayPolicy().getRefreshRatePolicy(); final int priority = refreshRatePolicy.calculatePriority(this); if (mFrameRateSelectionPriority != priority) { mFrameRateSelectionPriority = priority; getPendingTransaction().setFrameRateSelectionPriority(mSurfaceControl, mFrameRateSelectionPriority); } final float refreshRate = refreshRatePolicy.getPreferredRefreshRate(this); if (mDenyListFrameRate != refreshRate) { mDenyListFrameRate = refreshRate; getPendingTransaction().setFrameRate( mSurfaceControl, mDenyListFrameRate, Surface.FRAME_RATE_COMPATIBILITY_EXACT); } } private void updateGlobalScaleIfNeeded() { Loading Loading
core/java/android/view/DisplayInfo.java +4 −3 Original line number Diff line number Diff line Loading @@ -547,16 +547,17 @@ public final class DisplayInfo implements Parcelable { * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable * mode could be found. */ public int findDefaultModeByRefreshRate(float refreshRate) { @Nullable public Display.Mode findDefaultModeByRefreshRate(float refreshRate) { Display.Mode[] modes = supportedModes; Display.Mode defaultMode = getDefaultMode(); for (int i = 0; i < modes.length; i++) { if (modes[i].matches( defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) { return modes[i].getModeId(); return modes[i]; } } return 0; return null; } /** Loading
core/java/android/view/Surface.java +9 −0 Original line number Diff line number Diff line Loading @@ -217,6 +217,15 @@ public class Surface implements Parcelable { */ public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; /** * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display * to operate at the exact frame rate. * * This is used internally by the platform and should not be used by apps. * @hide */ public static final int FRAME_RATE_COMPATIBILITY_EXACT = 100; /** * Create an empty surface, which will later be filled in by readFromParcel(). * @hide Loading
services/core/java/com/android/server/display/DisplayManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -1357,7 +1357,7 @@ public final class DisplayManagerService extends SystemService { // Scan supported modes returned by display.getInfo() to find a mode with the same // size as the default display mode but with the specified refresh rate instead. requestedModeId = display.getDisplayInfoLocked().findDefaultModeByRefreshRate( requestedRefreshRate); requestedRefreshRate).getModeId(); } mDisplayModeDirector.getAppRequestObserver().setAppRequestedMode( displayId, requestedModeId); Loading
services/core/java/com/android/server/wm/RefreshRatePolicy.java +18 −8 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ import android.view.DisplayInfo; */ class RefreshRatePolicy { private final int mLowRefreshRateId; private final Mode mLowRefreshRateMode; private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>(); private final HighRefreshRateDenylist mHighRefreshRateDenylist; private final WindowManagerService mWmService; Loading Loading @@ -56,7 +56,7 @@ class RefreshRatePolicy { RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo, HighRefreshRateDenylist denylist) { mLowRefreshRateId = findLowRefreshRateModeId(displayInfo); mLowRefreshRateMode = findLowRefreshRateMode(displayInfo); mHighRefreshRateDenylist = denylist; mWmService = wmService; } Loading @@ -65,7 +65,7 @@ class RefreshRatePolicy { * Finds the mode id with the lowest refresh rate which is >= 60hz and same resolution as the * default mode. */ private int findLowRefreshRateModeId(DisplayInfo displayInfo) { private Mode findLowRefreshRateMode(DisplayInfo displayInfo) { Mode mode = displayInfo.getDefaultMode(); float[] refreshRates = displayInfo.getDefaultRefreshRates(); float bestRefreshRate = mode.getRefreshRate(); Loading Loading @@ -104,13 +104,9 @@ class RefreshRatePolicy { // If app is using Camera, force it to default (lower) refresh rate. if (mNonHighRefreshRatePackages.contains(packageName)) { return mLowRefreshRateId; return mLowRefreshRateMode.getModeId(); } // If app is denylisted using higher refresh rate, return default (lower) refresh rate if (mHighRefreshRateDenylist.isDenylisted(packageName)) { return mLowRefreshRateId; } return 0; } Loading @@ -137,4 +133,18 @@ class RefreshRatePolicy { } return LAYER_PRIORITY_UNSET; } float getPreferredRefreshRate(WindowState w) { // If app is animating, it's not able to control refresh rate because we want the animation // to run in default refresh rate. if (w.isAnimating(TRANSITION | PARENTS)) { return 0; } final String packageName = w.getOwningPackage(); if (mHighRefreshRateDenylist.isDenylisted(packageName)) { return mLowRefreshRateMode.getRefreshRate(); } return 0; } }
services/core/java/com/android/server/wm/WindowState.java +18 −3 Original line number Diff line number Diff line Loading @@ -233,6 +233,7 @@ import android.view.InputWindowHandle; import android.view.InsetsSource; import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.Surface; import android.view.Surface.Rotation; import android.view.SurfaceControl; import android.view.SurfaceSession; Loading Loading @@ -730,6 +731,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET; /** * This is the frame rate which is passed to SurfaceFlinger if the window is part of the * high refresh rate deny list. The variable is cached, so we do not send too many updates to * SF. */ float mDenyListFrameRate = 0f; static final int BLAST_TIMEOUT_DURATION = 5000; /* milliseconds */ private final WindowProcessController mWpcForDisplayAreaConfigChanges; Loading Loading @@ -5233,7 +5241,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mOwnerCanUseBackgroundBlur; } /** * Notifies SF about the priority of the window, if it changed. SF then uses this information * to decide which window's desired rendering rate should have a priority when deciding about Loading @@ -5242,13 +5249,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ @VisibleForTesting void updateFrameRateSelectionPriorityIfNeeded() { final int priority = getDisplayContent().getDisplayPolicy().getRefreshRatePolicy() .calculatePriority(this); RefreshRatePolicy refreshRatePolicy = getDisplayContent().getDisplayPolicy().getRefreshRatePolicy(); final int priority = refreshRatePolicy.calculatePriority(this); if (mFrameRateSelectionPriority != priority) { mFrameRateSelectionPriority = priority; getPendingTransaction().setFrameRateSelectionPriority(mSurfaceControl, mFrameRateSelectionPriority); } final float refreshRate = refreshRatePolicy.getPreferredRefreshRate(this); if (mDenyListFrameRate != refreshRate) { mDenyListFrameRate = refreshRate; getPendingTransaction().setFrameRate( mSurfaceControl, mDenyListFrameRate, Surface.FRAME_RATE_COMPATIBILITY_EXACT); } } private void updateGlobalScaleIfNeeded() { Loading