summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/display/BrightnessSynchronizer.java77
-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.java1
-rw-r--r--services/core/java/com/android/server/display/RampAnimator.java2
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java2
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java46
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java10
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