From 39b0311db8bd933dd2201a1751a560b05d75eea4 Mon Sep 17 00:00:00 2001 From: Christine Franks Date: Tue, 3 Jul 2018 14:46:07 -0700 Subject: [PATCH] Add IColorDisplayManager - Add IColorDisplayManager - Add CONTROL_DISPLAY_COLOR_TRANSFORMS permission Bug: 111215474 Test: atest FrameworksServicesTest:ColorDisplayServiceTest Change-Id: Ia8182ccc80c1733f00c62b136e7950e2d2092d75 --- Android.bp | 1 + api/system-current.txt | 1 + .../android/app/SystemServiceRegistry.java | 9 +++ core/java/android/content/Context.java | 11 ++++ .../hardware/display/ColorDisplayManager.java | 61 +++++++++++++++++++ .../display/IColorDisplayManager.aidl | 22 +++++++ core/res/AndroidManifest.xml | 7 +++ data/etc/privapp-permissions-platform.xml | 2 + packages/SystemUI/AndroidManifest.xml | 3 + .../server/display/ColorDisplayService.java | 40 ++++++++---- .../display/DisplayTransformManager.java | 34 +++++++++-- .../tests/servicestests/AndroidManifest.xml | 1 + .../display/ColorDisplayServiceTest.java | 38 ++++++++++-- 13 files changed, 210 insertions(+), 20 deletions(-) create mode 100644 core/java/android/hardware/display/IColorDisplayManager.aidl diff --git a/Android.bp b/Android.bp index 839d4cd4f78f..4bfb30c45070 100644 --- a/Android.bp +++ b/Android.bp @@ -162,6 +162,7 @@ java_defaults { "core/java/android/hardware/biometrics/IBiometricService.aidl", "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl", "core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl", + "core/java/android/hardware/display/IColorDisplayManager.aidl", "core/java/android/hardware/display/IDisplayManager.aidl", "core/java/android/hardware/display/IDisplayManagerCallback.aidl", "core/java/android/hardware/display/IVirtualDisplayCallback.aidl", diff --git a/api/system-current.txt b/api/system-current.txt index a53ab3ecdaf1..57330bed75d3 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -56,6 +56,7 @@ package android { field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; field public static final java.lang.String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL"; field public static final java.lang.String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"; + field public static final java.lang.String CONTROL_DISPLAY_COLOR_TRANSFORMS = "android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS"; field public static final java.lang.String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION"; field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE"; field public static final java.lang.String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 0123551230b0..6f71b7a06464 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -59,6 +59,7 @@ import android.hardware.SystemSensorManager; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.IBiometricService; import android.hardware.camera2.CameraManager; +import android.hardware.display.ColorDisplayManager; import android.hardware.display.DisplayManager; import android.hardware.face.FaceManager; import android.hardware.face.IFaceService; @@ -385,6 +386,14 @@ final class SystemServiceRegistry { return new DisplayManager(ctx.getOuterContext()); }}); + registerService(Context.COLOR_DISPLAY_SERVICE, ColorDisplayManager.class, + new CachedServiceFetcher() { + @Override + public ColorDisplayManager createService(ContextImpl ctx) { + return new ColorDisplayManager(); + } + }); + // InputMethodManager has its own cache strategy based on display id to support apps that // still assume InputMethodManager is a per-process singleton and it's safe to directly // access internal fields via reflection. Hence directly use ServiceFetcher instead of diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index cec8ef59b961..72964c739c24 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3120,6 +3120,7 @@ public abstract class Context { //@hide: HDMI_CONTROL_SERVICE, INPUT_SERVICE, DISPLAY_SERVICE, + //@hide COLOR_DISPLAY_SERVICE, USER_SERVICE, RESTRICTIONS_SERVICE, APP_OPS_SERVICE, @@ -4099,6 +4100,16 @@ public abstract class Context { */ public static final String DISPLAY_SERVICE = "display"; + /** + * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.hardware.display.ColorDisplayManager} for controlling color transforms. + * + * @see #getSystemService(String) + * @see android.hardware.display.ColorDisplayManager + * @hide + */ + public static final String COLOR_DISPLAY_SERVICE = "color_display"; + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.os.UserManager} for managing users on devices that support multiple users. diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java index 0a76c2bc724e..a4c1332b45d1 100644 --- a/core/java/android/hardware/display/ColorDisplayManager.java +++ b/core/java/android/hardware/display/ColorDisplayManager.java @@ -16,20 +16,81 @@ package android.hardware.display; +import android.annotation.RequiresPermission; +import android.annotation.SystemService; import android.content.Context; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.ServiceManager.ServiceNotFoundException; import com.android.internal.R; /** * Manages the display's color transforms and modes. + * * @hide */ +@SystemService(Context.COLOR_DISPLAY_SERVICE) public final class ColorDisplayManager { + private final ColorDisplayManagerInternal mManager; + + /** + * @hide + */ + public ColorDisplayManager() { + mManager = ColorDisplayManagerInternal.getInstance(); + } + + /** + * Returns whether the device has a wide color gamut display. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) + public boolean isDeviceColorManaged() { + return mManager.isDeviceColorManaged(); + } + /** * Returns {@code true} if Night Display is supported by the device. */ public static boolean isNightDisplayAvailable(Context context) { return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable); } + + private static class ColorDisplayManagerInternal { + + private static ColorDisplayManagerInternal sInstance; + + private final IColorDisplayManager mCdm; + + private ColorDisplayManagerInternal(IColorDisplayManager colorDisplayManager) { + mCdm = colorDisplayManager; + } + + public static ColorDisplayManagerInternal getInstance() { + synchronized (ColorDisplayManagerInternal.class) { + if (sInstance == null) { + try { + IBinder b = ServiceManager.getServiceOrThrow(Context.COLOR_DISPLAY_SERVICE); + sInstance = new ColorDisplayManagerInternal( + IColorDisplayManager.Stub.asInterface(b)); + } catch (ServiceNotFoundException e) { + throw new IllegalStateException(e); + } + } + return sInstance; + } + } + + boolean isDeviceColorManaged() { + try { + return mCdm.isDeviceColorManaged(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } } diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl new file mode 100644 index 000000000000..f7865899812a --- /dev/null +++ b/core/java/android/hardware/display/IColorDisplayManager.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.display; + +/** @hide */ +interface IColorDisplayManager { + boolean isDeviceColorManaged(); +} \ No newline at end of file diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 8c5b6f4765fb..eacdfa3100db 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3321,6 +3321,13 @@ + + + + + diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java index 0b6786cf8c07..521fa236cf7d 100644 --- a/services/core/java/com/android/server/display/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/ColorDisplayService.java @@ -16,6 +16,8 @@ package com.android.server.display; +import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TypeEvaluator; @@ -29,8 +31,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; +import android.hardware.display.IColorDisplayManager; import android.net.Uri; import android.opengl.Matrix; +import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; @@ -39,6 +43,7 @@ import android.util.MathUtils; import android.util.Slog; import android.view.animation.AnimationUtils; +import com.android.internal.R; import com.android.internal.app.ColorDisplayController; import com.android.server.SystemService; import com.android.server.twilight.TwilightListener; @@ -49,12 +54,8 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; -import com.android.internal.R; - -import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; - /** - * Tints the display at night. + * Controls the display's color transforms. */ public final class ColorDisplayService extends SystemService implements ColorDisplayController.Callback { @@ -101,7 +102,7 @@ public final class ColorDisplayService extends SystemService @Override public void onStart() { - // Nothing to publish. + publishBinderService(Context.COLOR_DISPLAY_SERVICE, new BinderService()); } @Override @@ -171,7 +172,7 @@ public final class ColorDisplayService extends SystemService } }; cr.registerContentObserver(Secure.getUriFor(Secure.USER_SETUP_COMPLETE), - false /* notifyForDescendents */, mUserSetupObserver, mCurrentUser); + false /* notifyForDescendants */, mUserSetupObserver, mCurrentUser); } else if (mBootCompleted) { setUp(); } @@ -405,8 +406,8 @@ public final class ColorDisplayService extends SystemService } /** - * Returns the first date time corresponding to the local time that occurs before the - * provided date time. + * Returns the first date time corresponding to the local time that occurs before the provided + * date time. * * @param compareTime the LocalDateTime to compare against * @return the prior LocalDateTime corresponding to this local time @@ -420,8 +421,8 @@ public final class ColorDisplayService extends SystemService } /** - * Returns the first date time corresponding to this local time that occurs after the - * provided date time. + * Returns the first date time corresponding to this local time that occurs after the provided + * date time. * * @param compareTime the LocalDateTime to compare against * @return the next LocalDateTime corresponding to this local time @@ -434,6 +435,11 @@ public final class ColorDisplayService extends SystemService return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt; } + private boolean isDeviceColorManagedInternal() { + final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); + return dtm.isDeviceColorManaged(); + } + private abstract class AutoMode implements ColorDisplayController.Callback { public abstract void onStart(); @@ -616,4 +622,16 @@ public final class ColorDisplayService extends SystemService return mResultMatrix; } } + + private final class BinderService extends IColorDisplayManager.Stub { + @Override + public boolean isDeviceColorManaged() { + final long token = Binder.clearCallingIdentity(); + try { + return isDeviceColorManagedInternal(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } } diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java index d6931e006479..5ca1755131ab 100644 --- a/services/core/java/com/android/server/display/DisplayTransformManager.java +++ b/services/core/java/com/android/server/display/DisplayTransformManager.java @@ -16,7 +16,6 @@ package com.android.server.display; -import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.opengl.Matrix; import android.os.IBinder; @@ -27,8 +26,10 @@ import android.os.SystemProperties; import android.util.Log; import android.util.Slog; import android.util.SparseArray; + import com.android.internal.annotations.GuardedBy; import com.android.internal.app.ColorDisplayController; + import java.util.Arrays; /** @@ -59,10 +60,6 @@ public class DisplayTransformManager { private static final int SURFACE_FLINGER_TRANSACTION_COLOR_MATRIX = 1015; private static final int SURFACE_FLINGER_TRANSACTION_DALTONIZER = 1014; - - private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation"; - private static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode"; - /** * SurfaceFlinger global saturation factor. */ @@ -71,6 +68,10 @@ public class DisplayTransformManager { * SurfaceFlinger display color (managed, unmanaged, etc.). */ private static final int SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR = 1023; + private static final int SURFACE_FLINGER_TRANSACTION_QUERY_WIDE_COLOR = 1030; + + private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation"; + private static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode"; private static final float COLOR_SATURATION_NATURAL = 1.0f; private static final float COLOR_SATURATION_BOOSTED = 1.1f; @@ -268,6 +269,29 @@ public class DisplayTransformManager { return true; } + /** + * Returns whether the screen is wide color gamut via SurfaceFlinger's + * {@link #SURFACE_FLINGER_TRANSACTION_QUERY_WIDE_COLOR}. + */ + public boolean isDeviceColorManaged() { + final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER); + if (flinger != null) { + final Parcel data = Parcel.obtain(); + final Parcel reply = Parcel.obtain(); + data.writeInterfaceToken("android.ui.ISurfaceComposer"); + try { + flinger.transact(SURFACE_FLINGER_TRANSACTION_QUERY_WIDE_COLOR, data, reply, 0); + return reply.readBoolean(); + } catch (RemoteException ex) { + Log.e(TAG, "Failed to query wide color support", ex); + } finally { + data.recycle(); + reply.recycle(); + } + } + return false; + } + /** * Propagates the provided saturation to the SurfaceFlinger. */ diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index fa17b6125983..42f75f0330ee 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -66,6 +66,7 @@ +