diff --git a/core/api/test-current.txt b/core/api/test-current.txt index e392ed7b6e2d9..51edd03515e11 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -18,6 +18,7 @@ package android { field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES"; field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS"; field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS"; + field public static final String MODIFY_REFRESH_RATE_SWITCHING_TYPE = "android.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE"; field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS"; field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK"; field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS"; @@ -743,9 +744,14 @@ package android.hardware.display { } public final class DisplayManager { + method @RequiresPermission(android.Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE) public int getRefreshRateSwitchingType(); method public boolean isMinimalPostProcessingRequested(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE) public void setRefreshRateSwitchingType(int); method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public void setShouldAlwaysRespectAppRequestedMode(boolean); method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public boolean shouldAlwaysRespectAppRequestedMode(); + field public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2; // 0x2 + field public static final int SWITCHING_TYPE_NONE = 0; // 0x0 + field public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1; // 0x1 field public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 512; // 0x200 field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400 } diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index ca5eeb1863c78..9bae1ff4b906e 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -19,6 +19,7 @@ package android.hardware.display; import static android.view.Display.DEFAULT_DISPLAY; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -38,9 +39,12 @@ import android.util.SparseArray; import android.view.Display; import android.view.Surface; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; + /** * Manages the properties of attached displays. */ @@ -336,6 +340,40 @@ public final class DisplayManager { */ public static final int VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP = 1 << 11; + + /** @hide */ + @IntDef(prefix = {"SWITCHING_TYPE_"}, value = { + SWITCHING_TYPE_NONE, + SWITCHING_TYPE_WITHIN_GROUPS, + SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SwitchingType {} + + /** + * No mode switching will happen. + * @hide + */ + @TestApi + public static final int SWITCHING_TYPE_NONE = 0; + + /** + * Allow only refresh rate switching between modes in the same configuration group. This way + * only switches without visual interruptions for the user will be allowed. + * @hide + */ + @TestApi + public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1; + + /** + * Allow refresh rate switching between all refresh rates even if the switch with have visual + * interruptions for the user. + * @hide + */ + @TestApi + public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2; + + /** @hide */ public DisplayManager(Context context) { mContext = context; @@ -874,6 +912,29 @@ public final class DisplayManager { return mGlobal.shouldAlwaysRespectAppRequestedMode(); } + /** + * Sets the refresh rate switching type. + * This matches {@link android.provider.Settings.Secure.MATCH_CONTENT_FRAME_RATE} + * + * @hide + */ + @TestApi + @RequiresPermission(Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE) + public void setRefreshRateSwitchingType(@SwitchingType int newValue) { + mGlobal.setRefreshRateSwitchingType(newValue); + } + + /** + * Returns the refresh rate switching type. + * + * @hide + */ + @TestApi + @RequiresPermission(Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE) + @SwitchingType public int getRefreshRateSwitchingType() { + return mGlobal.getRefreshRateSwitchingType(); + } + /** * Listens for changes in available display devices. */ diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 7b4889f0a1b3b..77ae9471dfb09 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -725,6 +725,33 @@ public final class DisplayManagerGlobal { } } + /** + * Sets the refresh rate switching type. + * + * @hide + */ + public void setRefreshRateSwitchingType(@DisplayManager.SwitchingType int newValue) { + try { + mDm.setRefreshRateSwitchingType(newValue); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * Returns the refresh rate switching type. + * + * @hide + */ + @DisplayManager.SwitchingType + public int getRefreshRateSwitchingType() { + try { + return mDm.getRefreshRateSwitchingType(); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub { @Override public void onDisplayEvent(int displayId, int event) { diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index 85da6424377aa..a9f78fa03a6db 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -134,4 +134,10 @@ interface IDisplayManager { // battery etc. void setShouldAlwaysRespectAppRequestedMode(boolean enabled); boolean shouldAlwaysRespectAppRequestedMode(); + + // Sets the refresh rate switching type. + void setRefreshRateSwitchingType(int newValue); + + // Returns the refresh rate switching type. + int getRefreshRateSwitchingType(); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 23e55cdf2a300..98f72552ed999 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4031,6 +4031,13 @@ + + + diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 2e3ea24f62e23..92b1ca731a309 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -332,6 +332,9 @@ + + + diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 29b413d921e18..d4a19d6bc366d 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -53,6 +53,7 @@ import android.hardware.display.AmbientBrightnessDayStats; import android.hardware.display.BrightnessChangeEvent; import android.hardware.display.BrightnessConfiguration; import android.hardware.display.Curve; +import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; @@ -1252,11 +1253,19 @@ public final class DisplayManagerService extends SystemService { mDisplayModeDirector.setShouldAlwaysRespectAppRequestedMode(enabled); } - boolean shouldAlwaysRespectAppRequestedModeInternal() { return mDisplayModeDirector.shouldAlwaysRespectAppRequestedMode(); } + void setRefreshRateSwitchingTypeInternal(@DisplayManager.SwitchingType int newValue) { + mDisplayModeDirector.setModeSwitchingType(newValue); + } + + @DisplayManager.SwitchingType + int getRefreshRateSwitchingTypeInternal() { + return mDisplayModeDirector.getModeSwitchingType(); + } + private void setBrightnessConfigurationForUserInternal( @Nullable BrightnessConfiguration c, @UserIdInt int userId, @Nullable String packageName) { @@ -2595,6 +2604,32 @@ public final class DisplayManagerService extends SystemService { } } + @Override // Binder call + public void setRefreshRateSwitchingType(int newValue) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE, + "Permission required to modify refresh rate switching type."); + final long token = Binder.clearCallingIdentity(); + try { + setRefreshRateSwitchingTypeInternal(newValue); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public int getRefreshRateSwitchingType() { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE, + "Permission required read refresh rate switching type."); + final long token = Binder.clearCallingIdentity(); + try { + return getRefreshRateSwitchingTypeInternal(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + private boolean validatePackageName(int uid, String packageName) { if (packageName != null) { String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 329081a8391fb..95918945eecd5 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -16,7 +16,6 @@ package com.android.server.display; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; @@ -53,8 +52,6 @@ import com.android.server.display.utils.AmbientFilterFactory; import com.android.server.utils.DeviceConfigInterface; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -110,28 +107,11 @@ public class DisplayModeDirector { private boolean mAlwaysRespectAppRequest; - @IntDef(prefix = {"SWITCHING_TYPE_"}, value = { - SWITCHING_TYPE_NONE, - SWITCHING_TYPE_WITHIN_GROUPS, - SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface SwitchingType {} - - // No mode switching will happen. - public static final int SWITCHING_TYPE_NONE = 0; - // Allow only refresh rate switching between modes in the same configuration group. This way - // only switches without visual interruptions for the user will be allowed. - public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1; - // Allow refresh rate switching between all refresh rates even if the switch with have visual - // interruptions for the user. - public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2; - /** * The allowed refresh rate switching type. This is used by SurfaceFlinger. */ - @SwitchingType - private int mModeSwitchingType = SWITCHING_TYPE_WITHIN_GROUPS; + @DisplayManager.SwitchingType + private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS; public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) { this(context, handler, new RealInjector()); @@ -337,7 +317,7 @@ public class DisplayModeDirector { if (availableModes.length > 0) { baseModeId = availableModes[0]; } - if (mModeSwitchingType == SWITCHING_TYPE_NONE) { + if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) { Display.Mode baseMode = null; for (Display.Mode mode : modes) { if (mode.getModeId() == baseModeId) { @@ -359,7 +339,7 @@ public class DisplayModeDirector { } boolean allowGroupSwitching = - mModeSwitchingType == SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS; + mModeSwitchingType == DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS; return new DesiredDisplayModeSpecs(baseModeId, allowGroupSwitching, new RefreshRateRange( @@ -450,18 +430,21 @@ public class DisplayModeDirector { /** * Sets the display mode switching type. - * @param type + * @param newType */ - public void setModeSwitchingType(@SwitchingType int type) { + public void setModeSwitchingType(@DisplayManager.SwitchingType int newType) { synchronized (mLock) { - mModeSwitchingType = type; + if (newType != mModeSwitchingType) { + mModeSwitchingType = newType; + notifyDesiredDisplayModeSpecsChangedLocked(); + } } } /** * Returns the display mode switching type. */ - @SwitchingType + @DisplayManager.SwitchingType public int getModeSwitchingType() { synchronized (mLock) { return mModeSwitchingType; @@ -583,13 +566,13 @@ public class DisplayModeDirector { } } - private static String switchingTypeToString(@SwitchingType int type) { + private static String switchingTypeToString(@DisplayManager.SwitchingType int type) { switch (type) { - case SWITCHING_TYPE_NONE: + case DisplayManager.SWITCHING_TYPE_NONE: return "SWITCHING_TYPE_NONE"; - case SWITCHING_TYPE_WITHIN_GROUPS: + case DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS: return "SWITCHING_TYPE_WITHIN_GROUPS"; - case SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS: + case DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS: return "SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS"; default: return "Unknown SwitchingType " + type; diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index cb5ca04c1fde3..603608b231723 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -40,6 +40,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.database.ContentObserver; +import android.hardware.display.DisplayManager; import android.hardware.Sensor; import android.hardware.SensorEventListener; import android.hardware.SensorManager; @@ -402,7 +403,7 @@ public class DisplayModeDirectorTest { director.injectVotesByDisplay(votesByDisplay); assertThat(director.getModeSwitchingType()) - .isNotEqualTo(DisplayModeDirector.SWITCHING_TYPE_NONE); + .isNotEqualTo(DisplayManager.SWITCHING_TYPE_NONE); DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30); @@ -411,9 +412,9 @@ public class DisplayModeDirectorTest { assertThat(desiredSpecs.appRequestRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); assertThat(desiredSpecs.baseModeId).isEqualTo(30); - director.setModeSwitchingType(DisplayModeDirector.SWITCHING_TYPE_NONE); + director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_NONE); assertThat(director.getModeSwitchingType()) - .isEqualTo(DisplayModeDirector.SWITCHING_TYPE_NONE); + .isEqualTo(DisplayManager.SWITCHING_TYPE_NONE); desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30); @@ -428,9 +429,9 @@ public class DisplayModeDirectorTest { final int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(0, 90); - director.setModeSwitchingType(DisplayModeDirector.SWITCHING_TYPE_WITHIN_GROUPS); + director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS); assertThat(director.getModeSwitchingType()) - .isEqualTo(DisplayModeDirector.SWITCHING_TYPE_WITHIN_GROUPS); + .isEqualTo(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS); DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); assertThat(desiredSpecs.allowGroupSwitching).isFalse(); } @@ -440,9 +441,9 @@ public class DisplayModeDirectorTest { final int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(0, 90); - director.setModeSwitchingType(DisplayModeDirector.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS); + director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS); assertThat(director.getModeSwitchingType()) - .isEqualTo(DisplayModeDirector.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS); + .isEqualTo(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS); DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); assertThat(desiredSpecs.allowGroupSwitching).isTrue(); }