Merge "Add ability to select composition color space for a given color mode" into qt-r1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b5f152e34d
@@ -1115,6 +1115,22 @@
|
||||
regularly selected color mode will be used if this value is negative. -->
|
||||
<integer name="config_accessibilityColorMode">-1</integer>
|
||||
|
||||
<!-- The following two arrays specify which color space to use for display composition when a
|
||||
certain color mode is active.
|
||||
Composition color spaces are defined in android.view.Display.COLOR_MODE_xxx, and color
|
||||
modes are defined in ColorDisplayManager.COLOR_MODE_xxx and
|
||||
ColorDisplayManager.VENDOR_COLOR_MODE_xxx.
|
||||
The color space COLOR_MODE_DEFAULT (0) lets the system select the most appropriate
|
||||
composition color space for currently displayed content. Other values (e.g.,
|
||||
COLOR_MODE_SRGB) override system selection; these other color spaces must be supported by
|
||||
the device for for display composition.
|
||||
If a color mode does not have a corresponding color space specified in this array, the
|
||||
currently set composition color space will not be modified.-->
|
||||
<integer-array name="config_displayCompositionColorModes">
|
||||
</integer-array>
|
||||
<integer-array name="config_displayCompositionColorSpaces">
|
||||
</integer-array>
|
||||
|
||||
<!-- Indicate whether to allow the device to suspend when the screen is off
|
||||
due to the proximity sensor. This resource should only be set to true
|
||||
if the sensor HAL correctly handles the proximity sensor as a wake-up source.
|
||||
|
||||
@@ -3192,6 +3192,8 @@
|
||||
<java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
|
||||
<java-symbol type="array" name="config_availableColorModes" />
|
||||
<java-symbol type="integer" name="config_accessibilityColorMode" />
|
||||
<java-symbol type="array" name="config_displayCompositionColorModes" />
|
||||
<java-symbol type="array" name="config_displayCompositionColorSpaces" />
|
||||
<java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
|
||||
<java-symbol type="bool" name="config_displayWhiteBalanceEnabledDefault" />
|
||||
<java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" />
|
||||
|
||||
@@ -63,6 +63,8 @@ import android.provider.Settings.Secure;
|
||||
import android.provider.Settings.System;
|
||||
import android.util.MathUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.Display;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.animation.AnimationUtils;
|
||||
@@ -171,6 +173,11 @@ public final class ColorDisplayService extends SystemService {
|
||||
|
||||
private NightDisplayAutoMode mNightDisplayAutoMode;
|
||||
|
||||
/**
|
||||
* Map of color modes -> display composition colorspace
|
||||
*/
|
||||
private SparseIntArray mColorModeCompositionColorSpaces = null;
|
||||
|
||||
public ColorDisplayService(Context context) {
|
||||
super(context);
|
||||
mHandler = new TintHandler(DisplayThread.get().getLooper());
|
||||
@@ -267,6 +274,30 @@ public final class ColorDisplayService extends SystemService {
|
||||
return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
|
||||
}
|
||||
|
||||
private void setUpDisplayCompositionColorSpaces(Resources res) {
|
||||
mColorModeCompositionColorSpaces = null;
|
||||
|
||||
final int[] colorModes = res.getIntArray(R.array.config_displayCompositionColorModes);
|
||||
if (colorModes == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int[] compSpaces = res.getIntArray(R.array.config_displayCompositionColorSpaces);
|
||||
if (compSpaces == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (colorModes.length != compSpaces.length) {
|
||||
Slog.e(TAG, "Number of composition color spaces doesn't match specified color modes");
|
||||
return;
|
||||
}
|
||||
|
||||
mColorModeCompositionColorSpaces = new SparseIntArray(colorModes.length);
|
||||
for (int i = 0; i < colorModes.length; i++) {
|
||||
mColorModeCompositionColorSpaces.put(colorModes[i], compSpaces[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUp() {
|
||||
Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
|
||||
|
||||
@@ -359,6 +390,8 @@ public final class ColorDisplayService extends SystemService {
|
||||
onAccessibilityInversionChanged();
|
||||
onAccessibilityDaltonizerChanged();
|
||||
|
||||
setUpDisplayCompositionColorSpaces(getContext().getResources());
|
||||
|
||||
// Set the color mode, if valid, and immediately apply the updated tint matrix based on the
|
||||
// existing activated state. This ensures consistency of tint across the color mode change.
|
||||
onDisplayColorModeChanged(getColorModeInternal());
|
||||
@@ -450,6 +483,14 @@ public final class ColorDisplayService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private int getCompositionColorSpace(int mode) {
|
||||
if (mColorModeCompositionColorSpaces == null) {
|
||||
return Display.COLOR_MODE_INVALID;
|
||||
}
|
||||
|
||||
return mColorModeCompositionColorSpaces.get(mode, Display.COLOR_MODE_INVALID);
|
||||
}
|
||||
|
||||
private void onDisplayColorModeChanged(int mode) {
|
||||
if (mode == NOT_SET) {
|
||||
return;
|
||||
@@ -470,7 +511,8 @@ public final class ColorDisplayService extends SystemService {
|
||||
// DisplayTransformManager.needsLinearColorMatrix(), therefore it is dependent
|
||||
// on the state of DisplayTransformManager.
|
||||
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
|
||||
dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
|
||||
dtm.setColorMode(mode, mNightDisplayTintController.getMatrix(),
|
||||
getCompositionColorSpace(mode));
|
||||
|
||||
if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
|
||||
updateDisplayWhiteBalanceStatus();
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Display;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -77,6 +78,8 @@ public class DisplayTransformManager {
|
||||
@VisibleForTesting
|
||||
static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
|
||||
@VisibleForTesting
|
||||
static final String PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE = "persist.sys.sf.color_mode";
|
||||
@VisibleForTesting
|
||||
static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
|
||||
|
||||
private static final float COLOR_SATURATION_NATURAL = 1.0f;
|
||||
@@ -251,23 +254,24 @@ public class DisplayTransformManager {
|
||||
/**
|
||||
* Sets color mode and updates night display transform values.
|
||||
*/
|
||||
public boolean setColorMode(int colorMode, float[] nightDisplayMatrix) {
|
||||
public boolean setColorMode(int colorMode, float[] nightDisplayMatrix,
|
||||
int compositionColorMode) {
|
||||
if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {
|
||||
applySaturation(COLOR_SATURATION_NATURAL);
|
||||
setDisplayColor(DISPLAY_COLOR_MANAGED);
|
||||
setDisplayColor(DISPLAY_COLOR_MANAGED, compositionColorMode);
|
||||
} else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
|
||||
applySaturation(COLOR_SATURATION_BOOSTED);
|
||||
setDisplayColor(DISPLAY_COLOR_MANAGED);
|
||||
setDisplayColor(DISPLAY_COLOR_MANAGED, compositionColorMode);
|
||||
} else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
|
||||
applySaturation(COLOR_SATURATION_NATURAL);
|
||||
setDisplayColor(DISPLAY_COLOR_UNMANAGED);
|
||||
setDisplayColor(DISPLAY_COLOR_UNMANAGED, compositionColorMode);
|
||||
} else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
|
||||
applySaturation(COLOR_SATURATION_NATURAL);
|
||||
setDisplayColor(DISPLAY_COLOR_ENHANCED);
|
||||
setDisplayColor(DISPLAY_COLOR_ENHANCED, compositionColorMode);
|
||||
} else if (colorMode >= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN
|
||||
&& colorMode <= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MAX) {
|
||||
applySaturation(COLOR_SATURATION_NATURAL);
|
||||
setDisplayColor(colorMode);
|
||||
setDisplayColor(colorMode, compositionColorMode);
|
||||
}
|
||||
|
||||
setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix);
|
||||
@@ -323,13 +327,21 @@ public class DisplayTransformManager {
|
||||
/**
|
||||
* Toggles native mode on/off in SurfaceFlinger.
|
||||
*/
|
||||
private void setDisplayColor(int color) {
|
||||
private void setDisplayColor(int color, int compositionColorMode) {
|
||||
SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, Integer.toString(color));
|
||||
if (compositionColorMode != Display.COLOR_MODE_INVALID) {
|
||||
SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE,
|
||||
Integer.toString(compositionColorMode));
|
||||
}
|
||||
|
||||
final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
|
||||
if (flinger != null) {
|
||||
final Parcel data = Parcel.obtain();
|
||||
data.writeInterfaceToken("android.ui.ISurfaceComposer");
|
||||
data.writeInt(color);
|
||||
if (compositionColorMode != Display.COLOR_MODE_INVALID) {
|
||||
data.writeInt(compositionColorMode);
|
||||
}
|
||||
try {
|
||||
flinger.transact(SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR, data, null, 0);
|
||||
} catch (RemoteException ex) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.display.color;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
|
||||
import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
|
||||
import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE;
|
||||
import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR;
|
||||
import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION;
|
||||
|
||||
@@ -28,6 +29,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
|
||||
import android.hardware.display.ColorDisplayManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.view.Display;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
@@ -79,7 +81,7 @@ public class DisplayTransformManagerTest {
|
||||
|
||||
@Test
|
||||
public void setColorMode_natural() {
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix);
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix, -1);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
|
||||
.isEqualTo("0" /* managed */);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
|
||||
@@ -88,7 +90,7 @@ public class DisplayTransformManagerTest {
|
||||
|
||||
@Test
|
||||
public void setColorMode_boosted() {
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix);
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix, -1);
|
||||
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
|
||||
.isEqualTo("0" /* managed */);
|
||||
@@ -98,7 +100,7 @@ public class DisplayTransformManagerTest {
|
||||
|
||||
@Test
|
||||
public void setColorMode_saturated() {
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix);
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix, -1);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
|
||||
.isEqualTo("1" /* unmanaged */);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
|
||||
@@ -107,7 +109,7 @@ public class DisplayTransformManagerTest {
|
||||
|
||||
@Test
|
||||
public void setColorMode_automatic() {
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix);
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix, -1);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
|
||||
.isEqualTo("2" /* enhanced */);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
|
||||
@@ -116,7 +118,7 @@ public class DisplayTransformManagerTest {
|
||||
|
||||
@Test
|
||||
public void setColorMode_vendor() {
|
||||
mDtm.setColorMode(0x100, mNightDisplayMatrix);
|
||||
mDtm.setColorMode(0x100, mNightDisplayMatrix, -1);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
|
||||
.isEqualTo(Integer.toString(0x100) /* pass-through */);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
|
||||
@@ -125,10 +127,38 @@ public class DisplayTransformManagerTest {
|
||||
|
||||
@Test
|
||||
public void setColorMode_outOfBounds() {
|
||||
mDtm.setColorMode(0x50, mNightDisplayMatrix);
|
||||
mDtm.setColorMode(0x50, mNightDisplayMatrix, -1);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
|
||||
.isEqualTo(null);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
|
||||
.isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setColorMode_withoutColorSpace() {
|
||||
String magicPropertyValue = "magic";
|
||||
|
||||
// Start with a known state, which we expect to remain unmodified
|
||||
SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
|
||||
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
|
||||
Display.COLOR_MODE_INVALID);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
|
||||
.isEqualTo(magicPropertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setColorMode_withColorSpace() {
|
||||
String magicPropertyValue = "magic";
|
||||
int testPropertyValue = Display.COLOR_MODE_SRGB;
|
||||
|
||||
// Start with a known state, which we expect to get modified
|
||||
SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
|
||||
|
||||
mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
|
||||
testPropertyValue);
|
||||
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
|
||||
.isEqualTo(Integer.toString(testPropertyValue));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,13 +18,19 @@ package com.android.server.display.color;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AlarmManager;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.display.ColorDisplayManager;
|
||||
import android.hardware.display.Time;
|
||||
import android.os.Handler;
|
||||
@@ -33,6 +39,7 @@ import android.provider.Settings;
|
||||
import android.provider.Settings.Secure;
|
||||
import android.provider.Settings.System;
|
||||
import android.test.mock.MockContentResolver;
|
||||
import android.view.Display;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
@@ -73,6 +80,8 @@ public class ColorDisplayServiceTest {
|
||||
private ColorDisplayService mCds;
|
||||
private ColorDisplayService.BinderService mBinderService;
|
||||
|
||||
private Resources mResourcesSpy;
|
||||
|
||||
@BeforeClass
|
||||
public static void setDtm() {
|
||||
final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
|
||||
@@ -84,6 +93,9 @@ public class ColorDisplayServiceTest {
|
||||
mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
|
||||
doReturn(mContext).when(mContext).getApplicationContext();
|
||||
|
||||
mResourcesSpy = Mockito.spy(mContext.getResources());
|
||||
when(mContext.getResources()).thenReturn(mResourcesSpy);
|
||||
|
||||
mUserId = ActivityManager.getCurrentUser();
|
||||
|
||||
final MockContentResolver cr = new MockContentResolver(mContext);
|
||||
@@ -1050,6 +1062,80 @@ public class ColorDisplayServiceTest {
|
||||
assertDwbActive(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositionColorSpaces_noResources() {
|
||||
final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
|
||||
reset(dtm);
|
||||
|
||||
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
|
||||
.thenReturn(new int[] {});
|
||||
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
|
||||
.thenReturn(new int[] {});
|
||||
setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
|
||||
startService();
|
||||
verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
|
||||
eq(Display.COLOR_MODE_INVALID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositionColorSpaces_invalidResources() {
|
||||
final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
|
||||
reset(dtm);
|
||||
|
||||
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
|
||||
.thenReturn(new int[] {
|
||||
ColorDisplayManager.COLOR_MODE_NATURAL,
|
||||
// Missing second color mode
|
||||
});
|
||||
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
|
||||
.thenReturn(new int[] {
|
||||
Display.COLOR_MODE_SRGB,
|
||||
Display.COLOR_MODE_DISPLAY_P3
|
||||
});
|
||||
setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
|
||||
startService();
|
||||
verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
|
||||
eq(Display.COLOR_MODE_INVALID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositionColorSpaces_validResources_validColorMode() {
|
||||
final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
|
||||
reset(dtm);
|
||||
|
||||
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
|
||||
.thenReturn(new int[] {
|
||||
ColorDisplayManager.COLOR_MODE_NATURAL
|
||||
});
|
||||
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
|
||||
.thenReturn(new int[] {
|
||||
Display.COLOR_MODE_SRGB,
|
||||
});
|
||||
setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
|
||||
startService();
|
||||
verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
|
||||
eq(Display.COLOR_MODE_SRGB));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositionColorSpaces_validResources_invalidColorMode() {
|
||||
final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
|
||||
reset(dtm);
|
||||
|
||||
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
|
||||
.thenReturn(new int[] {
|
||||
ColorDisplayManager.COLOR_MODE_NATURAL
|
||||
});
|
||||
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
|
||||
.thenReturn(new int[] {
|
||||
Display.COLOR_MODE_SRGB,
|
||||
});
|
||||
setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
|
||||
startService();
|
||||
verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(),
|
||||
eq(Display.COLOR_MODE_INVALID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Night display to use a custom schedule.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user