diff options
| -rw-r--r-- | core/java/com/android/internal/display/BrightnessSynchronizer.java | 77 | ||||
| -rw-r--r-- | core/java/com/android/internal/display/BrightnessUtils.java (renamed from services/core/java/com/android/server/display/BrightnessUtils.java) | 4 | ||||
| -rw-r--r-- | services/core/java/com/android/server/display/BrightnessMappingStrategy.java | 1 | ||||
| -rw-r--r-- | services/core/java/com/android/server/display/RampAnimator.java | 2 | ||||
| -rw-r--r-- | services/core/java/com/android/server/policy/PhoneWindowManager.java | 2 | ||||
| -rw-r--r-- | services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java | 46 | ||||
| -rw-r--r-- | services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java | 10 |
7 files changed, 115 insertions, 27 deletions
diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java index d503904c2e3c..7a87c3a82e43 100644 --- a/core/java/com/android/internal/display/BrightnessSynchronizer.java +++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java @@ -16,9 +16,11 @@ package com.android.internal.display; +import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; +import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.net.Uri; @@ -54,8 +56,7 @@ public class BrightnessSynchronizer { private static final int MSG_RUN_UPDATE = 1; // The tolerance within which we consider brightness values approximately equal to eachother. - // This value is approximately 1/3 of the smallest possible brightness value. - public static final float EPSILON = 0.001f; + public static final float EPSILON = 0.0001f; private static int sBrightnessUpdateCount = 1; @@ -284,6 +285,74 @@ public class BrightnessSynchronizer { } /** + * Converts between the int brightness setting and the float brightness system. The int + * brightness setting is between 0-255 and matches the brightness slider - e.g. 128 is 50% on + * the slider. Accounts for special values such as OFF and invalid values. Accounts for + * brightness limits; the maximum value here represents the max value allowed on the slider. + */ + @VisibleForTesting + @SuppressLint("AndroidFrameworkRequiresPermission") + public float brightnessIntSettingToFloat(int brightnessInt) { + if (brightnessInt == PowerManager.BRIGHTNESS_OFF) { + return PowerManager.BRIGHTNESS_OFF_FLOAT; + } else if (brightnessInt == PowerManager.BRIGHTNESS_INVALID) { + return PowerManager.BRIGHTNESS_INVALID_FLOAT; + } else { + final float minInt = PowerManager.BRIGHTNESS_OFF + 1; + final float maxInt = PowerManager.BRIGHTNESS_ON; + + // Normalize to the range [0, 1] + float userPerceptionBrightness = MathUtils.norm(minInt, maxInt, brightnessInt); + + // Convert from user-perception to linear scale + float linearBrightness = BrightnessUtils.convertGammaToLinear(userPerceptionBrightness); + + // Interpolate to the range [0, currentlyAllowedMax] + final Display display = mContext.getDisplay(); + if (display == null) { + return PowerManager.BRIGHTNESS_INVALID_FLOAT; + } + final BrightnessInfo info = display.getBrightnessInfo(); + return MathUtils.lerp(info.brightnessMinimum, info.brightnessMaximum, linearBrightness); + } + } + + /** + * Translates specified value from the float brightness system to the setting int brightness + * system. The value returned is between 0-255 and matches the brightness slider - e.g. 128 is + * 50% on the slider. Accounts for special values such as OFF and invalid values. Accounts for + * brightness limits; the maximum value here represents the max value currently allowed on + * the slider. + */ + @VisibleForTesting + @SuppressLint("AndroidFrameworkRequiresPermission") + public int brightnessFloatToIntSetting(float brightnessFloat) { + if (floatEquals(brightnessFloat, PowerManager.BRIGHTNESS_OFF_FLOAT)) { + return PowerManager.BRIGHTNESS_OFF; + } else if (Float.isNaN(brightnessFloat)) { + return PowerManager.BRIGHTNESS_INVALID; + } else { + // Normalize to the range [0, 1] + final Display display = mContext.getDisplay(); + if (display == null) { + return PowerManager.BRIGHTNESS_INVALID; + } + final BrightnessInfo info = display.getBrightnessInfo(); + float linearBrightness = + MathUtils.norm(info.brightnessMinimum, info.brightnessMaximum, brightnessFloat); + + // Convert from linear to user-perception scale + float userPerceptionBrightness = BrightnessUtils.convertLinearToGamma(linearBrightness); + + // Interpolate to the range [0, 255] + final float minInt = PowerManager.BRIGHTNESS_OFF + 1; + final float maxInt = PowerManager.BRIGHTNESS_ON; + float intBrightness = MathUtils.lerp(minInt, maxInt, userPerceptionBrightness); + return Math.round(intBrightness); + } + } + + /** * Encapsulates a brightness change event and contains logic for synchronizing the appropriate * settings for the specified brightness change. */ @@ -421,14 +490,14 @@ public class BrightnessSynchronizer { if (mSourceType == TYPE_INT) { return (int) mBrightness; } - return brightnessFloatToInt(mBrightness); + return brightnessFloatToIntSetting(mBrightness); } private float getBrightnessAsFloat() { if (mSourceType == TYPE_FLOAT) { return mBrightness; } - return brightnessIntToFloat((int) mBrightness); + return brightnessIntSettingToFloat((int) mBrightness); } private String toStringLabel(int type, float brightness) { diff --git a/services/core/java/com/android/server/display/BrightnessUtils.java b/core/java/com/android/internal/display/BrightnessUtils.java index 84fa0cccbd10..82b506bed80b 100644 --- a/services/core/java/com/android/server/display/BrightnessUtils.java +++ b/core/java/com/android/internal/display/BrightnessUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.display; +package com.android.internal.display; import android.util.MathUtils; diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index 99a5398aa7ee..debf828abf0a 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -33,6 +33,7 @@ import android.util.Spline; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.display.BrightnessSynchronizer; +import com.android.internal.display.BrightnessUtils; import com.android.internal.util.Preconditions; import com.android.server.display.utils.Plog; import com.android.server.display.whitebalance.DisplayWhiteBalanceController; diff --git a/services/core/java/com/android/server/display/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java index 5ba042c51a45..e38c2c58f453 100644 --- a/services/core/java/com/android/server/display/RampAnimator.java +++ b/services/core/java/com/android/server/display/RampAnimator.java @@ -20,6 +20,8 @@ import android.animation.ValueAnimator; import android.util.FloatProperty; import android.view.Choreographer; +import com.android.internal.display.BrightnessUtils; + /** * A custom animator that progressively updates a property value at * a given variable rate until it reaches a particular target value. diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 097656cac7f7..dfc9b8b030f2 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -198,6 +198,7 @@ import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.AssistUtils; +import com.android.internal.display.BrightnessUtils; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; @@ -217,7 +218,6 @@ import com.android.server.GestureLauncherService; import com.android.server.LocalServices; import com.android.server.SystemServiceManager; import com.android.server.UiThread; -import com.android.server.display.BrightnessUtils; import com.android.server.input.InputManagerInternal; import com.android.server.input.KeyboardMetricsCollector; import com.android.server.input.KeyboardMetricsCollector.KeyboardLogEvent; diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java index 2fd6e5fb6892..7a4327cc0598 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java @@ -19,6 +19,7 @@ package com.android.server.display; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.isA; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -27,15 +28,18 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.ContextWrapper; import android.database.ContentObserver; +import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.net.Uri; import android.os.Handler; +import android.os.PowerManager; import android.os.UserHandle; import android.os.test.TestLooper; import android.provider.Settings; import android.test.mock.MockContentResolver; import android.view.Display; +import android.view.DisplayAdjustments; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; @@ -59,6 +63,7 @@ public class BrightnessSynchronizerTest { private static final float EPSILON = 0.00001f; private static final Uri BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS); + private static final float BRIGHTNESS_MAX = 0.6f; private Context mContext; private MockContentResolver mContentResolverSpy; @@ -66,6 +71,7 @@ public class BrightnessSynchronizerTest { private DisplayListener mDisplayListener; private ContentObserver mContentObserver; private TestLooper mTestLooper; + private BrightnessSynchronizer mSynchronizer; @Mock private DisplayManager mDisplayManagerMock; @Captor private ArgumentCaptor<DisplayListener> mDisplayListenerCaptor; @@ -74,7 +80,17 @@ public class BrightnessSynchronizerTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); + + Display display = mock(Display.class); + when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments()); + BrightnessInfo info = new BrightnessInfo(PowerManager.BRIGHTNESS_INVALID_FLOAT, + PowerManager.BRIGHTNESS_MIN, BRIGHTNESS_MAX, + BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, BRIGHTNESS_MAX, + BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE); + when(display.getBrightnessInfo()).thenReturn(info); + + mContext = spy(new ContextWrapper( + ApplicationProvider.getApplicationContext().createDisplayContext(display))); mContentResolverSpy = spy(new MockContentResolver(mContext)); mContentResolverSpy.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mContentResolverSpy); @@ -128,13 +144,12 @@ public class BrightnessSynchronizerTest { @Test public void testSetSameIntValue_nothingUpdated() { putFloatSetting(0.5f); - putIntSetting(128); start(); - putIntSetting(128); + putIntSetting(fToI(0.5f)); advanceTime(10); verify(mDisplayManagerMock, times(0)).setBrightness( - eq(Display.DEFAULT_DISPLAY), eq(iToF(128))); + eq(Display.DEFAULT_DISPLAY), eq(0.5f)); } @Test @@ -154,14 +169,13 @@ public class BrightnessSynchronizerTest { // Verify that this update did not get sent to float, because synchronizer // is still waiting for confirmation of its first value. verify(mDisplayManagerMock, times(0)).setBrightness( - eq(Display.DEFAULT_DISPLAY), eq(iToF(20))); + Display.DEFAULT_DISPLAY, iToF(20)); // Send the confirmation of the initial change. This should trigger the new value to // finally be processed and we can verify that the new value (20) is sent. putIntSetting(fToI(0.4f)); advanceTime(10); - verify(mDisplayManagerMock).setBrightness( - eq(Display.DEFAULT_DISPLAY), eq(iToF(20))); + verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, iToF(20)); } @@ -183,8 +197,7 @@ public class BrightnessSynchronizerTest { advanceTime(200); // Verify that the new value gets sent because the timeout expired. - verify(mDisplayManagerMock).setBrightness( - eq(Display.DEFAULT_DISPLAY), eq(iToF(20))); + verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, iToF(20)); // Send a confirmation of the initial event, BrightnessSynchronizer should treat this as a // new event because the timeout had already expired @@ -196,14 +209,14 @@ public class BrightnessSynchronizerTest { // Verify we sent what would have been the confirmation as a new event to displaymanager. // We do both fToI and iToF because the conversions are not symmetric. - verify(mDisplayManagerMock).setBrightness( - eq(Display.DEFAULT_DISPLAY), eq(iToF(fToI(0.4f)))); + verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, + iToF(fToI(0.4f))); } - private BrightnessSynchronizer start() { - BrightnessSynchronizer bs = new BrightnessSynchronizer(mContext, mTestLooper.getLooper(), + private void start() { + mSynchronizer = new BrightnessSynchronizer(mContext, mTestLooper.getLooper(), mClock::now); - bs.startSynchronizing(); + mSynchronizer.startSynchronizing(); verify(mDisplayManagerMock).registerDisplayListener(mDisplayListenerCaptor.capture(), isA(Handler.class), eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); mDisplayListener = mDisplayListenerCaptor.getValue(); @@ -211,7 +224,6 @@ public class BrightnessSynchronizerTest { verify(mContentResolverSpy).registerContentObserver(eq(BRIGHTNESS_URI), eq(false), mContentObserverCaptor.capture(), eq(UserHandle.USER_ALL)); mContentObserver = mContentObserverCaptor.getValue(); - return bs; } private int getIntSetting() throws Exception { @@ -241,11 +253,11 @@ public class BrightnessSynchronizerTest { } private int fToI(float brightness) { - return BrightnessSynchronizer.brightnessFloatToInt(brightness); + return mSynchronizer.brightnessFloatToIntSetting(brightness); } private float iToF(int brightness) { - return BrightnessSynchronizer.brightnessIntToFloat(brightness); + return mSynchronizer.brightnessIntSettingToFloat(brightness); } private void advanceTime(long timeMs) { diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index 2396905aecbf..306de525e53c 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -71,6 +71,7 @@ import android.graphics.Rect; import android.hardware.Sensor; import android.hardware.SensorManager; import android.hardware.display.BrightnessConfiguration; +import android.hardware.display.BrightnessInfo; import android.hardware.display.Curve; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; @@ -94,6 +95,7 @@ import android.os.Process; import android.os.RemoteException; import android.view.ContentRecordingSession; import android.view.Display; +import android.view.DisplayAdjustments; import android.view.DisplayCutout; import android.view.DisplayEventReceiver; import android.view.DisplayInfo; @@ -101,7 +103,6 @@ import android.view.Surface; import android.view.SurfaceControl; import android.window.DisplayWindowPolicyController; -import androidx.test.InstrumentationRegistry; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; @@ -332,7 +333,11 @@ public class DisplayManagerServiceTest { LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal); // TODO: b/287945043 - mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); + Display display = mock(Display.class); + when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments()); + when(display.getBrightnessInfo()).thenReturn(mock(BrightnessInfo.class)); + mContext = spy(new ContextWrapper( + ApplicationProvider.getApplicationContext().createDisplayContext(display))); mResources = Mockito.spy(mContext.getResources()); manageDisplaysPermission(/* granted= */ false); when(mContext.getResources()).thenReturn(mResources); @@ -1907,7 +1912,6 @@ public class DisplayManagerServiceTest { @Test public void testSettingTwoBrightnessConfigurationsOnMultiDisplay() { - Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); // get the first two internal displays |