Loading core/java/android/hardware/display/DisplayManager.java +15 −1 Original line number Diff line number Diff line Loading @@ -541,7 +541,8 @@ public final class DisplayManager { EVENT_FLAG_DISPLAY_ADDED, EVENT_FLAG_DISPLAY_CHANGED, EVENT_FLAG_DISPLAY_REMOVED, EVENT_FLAG_DISPLAY_BRIGHTNESS EVENT_FLAG_DISPLAY_BRIGHTNESS, EVENT_FLAG_HDR_SDR_RATIO_CHANGED }) @Retention(RetentionPolicy.SOURCE) public @interface EventsMask {} Loading Loading @@ -584,6 +585,19 @@ public final class DisplayManager { */ public static final long EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 3; /** * Event flag to register for a display's hdr/sdr ratio changes. This notification is sent * through the {@link DisplayListener#onDisplayChanged} callback method. New hdr/sdr * values can be retrieved via {@link Display#getHdrSdrRatio()}. * * Requires that {@link Display#isHdrSdrRatioAvailable()} is true. * * @see #registerDisplayListener(DisplayListener, Handler, long) * * @hide */ public static final long EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 4; /** @hide */ public DisplayManager(Context context) { mContext = context; Loading core/java/android/hardware/display/DisplayManagerGlobal.java +53 −19 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.hardware.graphics.common.DisplayDecorationSupport; import android.media.projection.IMediaProjection; import android.media.projection.MediaProjection; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.Looper; import android.os.Message; Loading @@ -56,11 +57,12 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicLong; /** * Manager communication with the display manager service on behalf of Loading @@ -82,11 +84,12 @@ public final class DisplayManagerGlobal { // orientation change before the display info cache has actually been invalidated. private static final boolean USE_CACHE = false; @IntDef(prefix = {"SWITCHING_TYPE_"}, value = { @IntDef(prefix = {"EVENT_DISPLAY_"}, flag = true, value = { EVENT_DISPLAY_ADDED, EVENT_DISPLAY_CHANGED, EVENT_DISPLAY_REMOVED, EVENT_DISPLAY_BRIGHTNESS_CHANGED EVENT_DISPLAY_BRIGHTNESS_CHANGED, EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED, }) @Retention(RetentionPolicy.SOURCE) public @interface DisplayEvent {} Loading @@ -95,6 +98,7 @@ public final class DisplayManagerGlobal { public static final int EVENT_DISPLAY_CHANGED = 2; public static final int EVENT_DISPLAY_REMOVED = 3; public static final int EVENT_DISPLAY_BRIGHTNESS_CHANGED = 4; public static final int EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED = 5; @UnsupportedAppUsage private static DisplayManagerGlobal sInstance; Loading @@ -109,7 +113,8 @@ public final class DisplayManagerGlobal { private DisplayManagerCallback mCallback; private @EventsMask long mRegisteredEventsMask = 0; private final ArrayList<DisplayListenerDelegate> mDisplayListeners = new ArrayList<>(); private final CopyOnWriteArrayList<DisplayListenerDelegate> mDisplayListeners = new CopyOnWriteArrayList<>(); private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>(); private final ColorSpace mWideColorSpace; Loading Loading @@ -315,6 +320,19 @@ public final class DisplayManagerGlobal { */ public void registerDisplayListener(@NonNull DisplayListener listener, @Nullable Handler handler, @EventsMask long eventsMask) { Looper looper = getLooperForHandler(handler); Handler springBoard = new Handler(looper); registerDisplayListener(listener, new HandlerExecutor(springBoard), eventsMask); } /** * Register a listener for display-related changes. * * @param listener The listener that will be called when display changes occur. * @param executor Executor for the thread that will be receiving the callbacks. Cannot be null. */ public void registerDisplayListener(@NonNull DisplayListener listener, @NonNull Executor executor, @EventsMask long eventsMask) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } Loading @@ -326,8 +344,7 @@ public final class DisplayManagerGlobal { synchronized (mLock) { int index = findDisplayListenerLocked(listener); if (index < 0) { Looper looper = getLooperForHandler(handler); mDisplayListeners.add(new DisplayListenerDelegate(listener, looper, eventsMask)); mDisplayListeners.add(new DisplayListenerDelegate(listener, executor, eventsMask)); registerCallbackIfNeededLocked(); } else { mDisplayListeners.get(index).setEventsMask(eventsMask); Loading Loading @@ -408,6 +425,7 @@ public final class DisplayManagerGlobal { } private void handleDisplayEvent(int displayId, @DisplayEvent int event) { final DisplayInfo info; synchronized (mLock) { if (USE_CACHE) { mDisplayInfoCache.remove(displayId); Loading @@ -417,11 +435,7 @@ public final class DisplayManagerGlobal { } } final int numListeners = mDisplayListeners.size(); DisplayInfo info = getDisplayInfo(displayId); for (int i = 0; i < numListeners; i++) { mDisplayListeners.get(i).sendDisplayEvent(displayId, event, info); } info = getDisplayInfoLocked(displayId); if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) { // Choreographer only supports a single display, so only dispatch refresh rate // changes for the default display. Loading @@ -438,6 +452,11 @@ public final class DisplayManagerGlobal { } } } // Accepting an Executor means the listener may be synchronously invoked, so we must // not be holding mLock when we do so for (DisplayListenerDelegate listener : mDisplayListeners) { listener.sendDisplayEvent(displayId, event, info); } } public void startWifiDisplayScan() { Loading Loading @@ -1088,34 +1107,42 @@ public final class DisplayManagerGlobal { } } private static final class DisplayListenerDelegate extends Handler { private static final class DisplayListenerDelegate { public final DisplayListener mListener; public volatile long mEventsMask; private final DisplayInfo mDisplayInfo = new DisplayInfo(); private final Executor mExecutor; private AtomicLong mGenerationId = new AtomicLong(1); DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper, DisplayListenerDelegate(DisplayListener listener, @NonNull Executor executor, @EventsMask long eventsMask) { super(looper, null, true /*async*/); mExecutor = executor; mListener = listener; mEventsMask = eventsMask; } public void sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info) { Message msg = obtainMessage(event, displayId, 0, info); sendMessage(msg); long generationId = mGenerationId.get(); Message msg = Message.obtain(null, event, displayId, 0, info); mExecutor.execute(() -> { // If the generation id's don't match we were canceled but still need to recycle() if (generationId == mGenerationId.get()) { handleMessage(msg); } msg.recycle(); }); } public void clearEvents() { removeCallbacksAndMessages(null); mGenerationId.incrementAndGet(); } public void setEventsMask(@EventsMask long newEventsMask) { mEventsMask = newEventsMask; } @Override public void handleMessage(Message msg) { private void handleMessage(Message msg) { if (DEBUG) { Trace.beginSection( "DisplayListenerDelegate(" + eventToString(msg.what) Loading Loading @@ -1147,6 +1174,11 @@ public final class DisplayManagerGlobal { mListener.onDisplayRemoved(msg.arg1); } break; case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: if ((mEventsMask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) { mListener.onDisplayChanged(msg.arg1); } break; } if (DEBUG) { Trace.endSection(); Loading Loading @@ -1268,6 +1300,8 @@ public final class DisplayManagerGlobal { return "REMOVED"; case EVENT_DISPLAY_BRIGHTNESS_CHANGED: return "BRIGHTNESS_CHANGED"; case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: return "HDR_SDR_RATIO_CHANGED"; } return "UNKNOWN"; } Loading core/java/android/view/Display.java +129 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * Provides information about the size and density of a logical display. Loading Loading @@ -111,6 +113,8 @@ public final class Display { private int mCachedAppWidthCompat; private int mCachedAppHeightCompat; private ArrayList<HdrSdrRatioListenerWrapper> mHdrSdrRatioListeners = new ArrayList<>(); /** * The default Display id, which is the id of the primary display assuming there is one. */ Loading Loading @@ -1291,6 +1295,102 @@ public final class Display { } } /** * @return Whether the display supports reporting an hdr/sdr ratio. If this is false, * {@link #getHdrSdrRatio()} will always be 1.0f * @hide * TODO: make public */ public boolean isHdrSdrRatioAvailable() { synchronized (mLock) { updateDisplayInfoLocked(); return !Float.isNaN(mDisplayInfo.hdrSdrRatio); } } /** * @return The current hdr/sdr ratio expressed as the ratio of targetHdrPeakBrightnessInNits / * targetSdrWhitePointInNits. If {@link #isHdrSdrRatioAvailable()} is false, this * always returns 1.0f. * * @hide * TODO: make public */ public float getHdrSdrRatio() { synchronized (mLock) { updateDisplayInfoLocked(); return Float.isNaN(mDisplayInfo.hdrSdrRatio) ? 1.0f : mDisplayInfo.hdrSdrRatio; } } private int findHdrSdrRatioListenerLocked(Consumer<Display> listener) { for (int i = 0; i < mHdrSdrRatioListeners.size(); i++) { final HdrSdrRatioListenerWrapper wrapper = mHdrSdrRatioListeners.get(i); if (wrapper.mListener == listener) { return i; } } return -1; } /** * Registers a listener that will be invoked whenever the display's hdr/sdr ratio has changed. * After receiving the callback on the specified Executor, call {@link #getHdrSdrRatio()} to * get the updated value. * If {@link #isHdrSdrRatioAvailable()} is false, then an IllegalStateException will be thrown * * @see #unregisterHdrSdrRatioChangedListener(Consumer) * @param executor The executor to invoke the listener on * @param listener The listener to invoke when the HDR/SDR ratio changes * @throws IllegalStateException if {@link #isHdrSdrRatioAvailable()} is false * @hide * TODO: Make public */ public void registerHdrSdrRatioChangedListener(@NonNull Executor executor, @NonNull Consumer<Display> listener) { if (!isHdrSdrRatioAvailable()) { throw new IllegalStateException("HDR/SDR ratio changed not available"); } HdrSdrRatioListenerWrapper toRegister = null; synchronized (mLock) { if (findHdrSdrRatioListenerLocked(listener) == -1) { toRegister = new HdrSdrRatioListenerWrapper(listener); mHdrSdrRatioListeners.add(toRegister); } // else already listening, don't do anything } if (toRegister != null) { // Although we only care about the HDR/SDR ratio changing, that can also come in the // form of the larger DISPLAY_CHANGED event mGlobal.registerDisplayListener(toRegister, executor, DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED | DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); } } /** * @param listener The previously * {@link #registerHdrSdrRatioChangedListener(Executor, Consumer) registered} * hdr/sdr ratio listener to remove. * * @see #registerHdrSdrRatioChangedListener(Executor, Consumer) * @hide * TODO: Make public */ public void unregisterHdrSdrRatioChangedListener(Consumer<Display> listener) { HdrSdrRatioListenerWrapper toRemove = null; synchronized (mLock) { int index = findHdrSdrRatioListenerLocked(listener); if (index != -1) { toRemove = mHdrSdrRatioListeners.remove(index); } } if (toRemove != null) { mGlobal.unregisterDisplayListener(toRemove); } } /** * Sets the default {@link Display.Mode} to use for the display. The display mode includes * preference for resolution and refresh rate. Loading Loading @@ -2528,4 +2628,33 @@ public final class Display { } } } private class HdrSdrRatioListenerWrapper implements DisplayManager.DisplayListener { Consumer<Display> mListener; float mLastReportedRatio = 1.f; private HdrSdrRatioListenerWrapper(Consumer<Display> listener) { mListener = listener; } @Override public void onDisplayAdded(int displayId) { // don't care } @Override public void onDisplayRemoved(int displayId) { // don't care } @Override public void onDisplayChanged(int displayId) { if (displayId == getDisplayId()) { float newRatio = getHdrSdrRatio(); if (newRatio != mLastReportedRatio) { mListener.accept(Display.this); } } } } } core/java/android/view/DisplayInfo.java +20 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,8 @@ import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.proto.ProtoOutputStream; import com.android.internal.display.BrightnessSynchronizer; import java.util.Arrays; import java.util.Objects; Loading Loading @@ -340,6 +342,13 @@ public final class DisplayInfo implements Parcelable { @Nullable public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate; /** * The current hdr/sdr ratio for the display. If the display doesn't support hdr/sdr ratio * queries then this is NaN */ public float hdrSdrRatio = Float.NaN; public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() { @Override public DisplayInfo createFromParcel(Parcel source) { Loading Loading @@ -415,7 +424,8 @@ public final class DisplayInfo implements Parcelable { && Objects.equals(roundedCorners, other.roundedCorners) && installOrientation == other.installOrientation && Objects.equals(displayShape, other.displayShape) && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate); && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate) && BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio); } @Override Loading Loading @@ -471,6 +481,7 @@ public final class DisplayInfo implements Parcelable { installOrientation = other.installOrientation; displayShape = other.displayShape; layoutLimitedRefreshRate = other.layoutLimitedRefreshRate; hdrSdrRatio = other.hdrSdrRatio; } public void readFromParcel(Parcel source) { Loading Loading @@ -532,6 +543,7 @@ public final class DisplayInfo implements Parcelable { installOrientation = source.readInt(); displayShape = source.readTypedObject(DisplayShape.CREATOR); layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR); hdrSdrRatio = source.readFloat(); } @Override Loading Loading @@ -591,6 +603,7 @@ public final class DisplayInfo implements Parcelable { dest.writeInt(installOrientation); dest.writeTypedObject(displayShape, flags); dest.writeTypedObject(layoutLimitedRefreshRate, flags); dest.writeFloat(hdrSdrRatio); } @Override Loading Loading @@ -852,6 +865,12 @@ public final class DisplayInfo implements Parcelable { sb.append(Surface.rotationToString(installOrientation)); sb.append(", layoutLimitedRefreshRate "); sb.append(layoutLimitedRefreshRate); sb.append(", hdrSdrRatio "); if (Float.isNaN(hdrSdrRatio)) { sb.append("not_available"); } else { sb.append(hdrSdrRatio); } sb.append("}"); return sb.toString(); } Loading services/core/java/com/android/server/display/DisplayDeviceConfig.java +2 −2 Original line number Diff line number Diff line Loading @@ -450,7 +450,7 @@ public class DisplayDeviceConfig { // so -2 is used instead private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f; private static final float NITS_INVALID = -1; static final float NITS_INVALID = -1; // Length of the ambient light horizon used to calculate the long term estimate of ambient // light. Loading Loading @@ -840,7 +840,7 @@ public class DisplayDeviceConfig { /** * Calculates the nits value for the specified backlight value if a mapping exists. * * @return The mapped nits or 0 if no mapping exits. * @return The mapped nits or {@link #NITS_INVALID} if no mapping exits. */ public float getNitsFromBacklight(float backlight) { if (mBacklightToNitsSpline == null) { Loading Loading
core/java/android/hardware/display/DisplayManager.java +15 −1 Original line number Diff line number Diff line Loading @@ -541,7 +541,8 @@ public final class DisplayManager { EVENT_FLAG_DISPLAY_ADDED, EVENT_FLAG_DISPLAY_CHANGED, EVENT_FLAG_DISPLAY_REMOVED, EVENT_FLAG_DISPLAY_BRIGHTNESS EVENT_FLAG_DISPLAY_BRIGHTNESS, EVENT_FLAG_HDR_SDR_RATIO_CHANGED }) @Retention(RetentionPolicy.SOURCE) public @interface EventsMask {} Loading Loading @@ -584,6 +585,19 @@ public final class DisplayManager { */ public static final long EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 3; /** * Event flag to register for a display's hdr/sdr ratio changes. This notification is sent * through the {@link DisplayListener#onDisplayChanged} callback method. New hdr/sdr * values can be retrieved via {@link Display#getHdrSdrRatio()}. * * Requires that {@link Display#isHdrSdrRatioAvailable()} is true. * * @see #registerDisplayListener(DisplayListener, Handler, long) * * @hide */ public static final long EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 4; /** @hide */ public DisplayManager(Context context) { mContext = context; Loading
core/java/android/hardware/display/DisplayManagerGlobal.java +53 −19 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.hardware.graphics.common.DisplayDecorationSupport; import android.media.projection.IMediaProjection; import android.media.projection.MediaProjection; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.Looper; import android.os.Message; Loading @@ -56,11 +57,12 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicLong; /** * Manager communication with the display manager service on behalf of Loading @@ -82,11 +84,12 @@ public final class DisplayManagerGlobal { // orientation change before the display info cache has actually been invalidated. private static final boolean USE_CACHE = false; @IntDef(prefix = {"SWITCHING_TYPE_"}, value = { @IntDef(prefix = {"EVENT_DISPLAY_"}, flag = true, value = { EVENT_DISPLAY_ADDED, EVENT_DISPLAY_CHANGED, EVENT_DISPLAY_REMOVED, EVENT_DISPLAY_BRIGHTNESS_CHANGED EVENT_DISPLAY_BRIGHTNESS_CHANGED, EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED, }) @Retention(RetentionPolicy.SOURCE) public @interface DisplayEvent {} Loading @@ -95,6 +98,7 @@ public final class DisplayManagerGlobal { public static final int EVENT_DISPLAY_CHANGED = 2; public static final int EVENT_DISPLAY_REMOVED = 3; public static final int EVENT_DISPLAY_BRIGHTNESS_CHANGED = 4; public static final int EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED = 5; @UnsupportedAppUsage private static DisplayManagerGlobal sInstance; Loading @@ -109,7 +113,8 @@ public final class DisplayManagerGlobal { private DisplayManagerCallback mCallback; private @EventsMask long mRegisteredEventsMask = 0; private final ArrayList<DisplayListenerDelegate> mDisplayListeners = new ArrayList<>(); private final CopyOnWriteArrayList<DisplayListenerDelegate> mDisplayListeners = new CopyOnWriteArrayList<>(); private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>(); private final ColorSpace mWideColorSpace; Loading Loading @@ -315,6 +320,19 @@ public final class DisplayManagerGlobal { */ public void registerDisplayListener(@NonNull DisplayListener listener, @Nullable Handler handler, @EventsMask long eventsMask) { Looper looper = getLooperForHandler(handler); Handler springBoard = new Handler(looper); registerDisplayListener(listener, new HandlerExecutor(springBoard), eventsMask); } /** * Register a listener for display-related changes. * * @param listener The listener that will be called when display changes occur. * @param executor Executor for the thread that will be receiving the callbacks. Cannot be null. */ public void registerDisplayListener(@NonNull DisplayListener listener, @NonNull Executor executor, @EventsMask long eventsMask) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } Loading @@ -326,8 +344,7 @@ public final class DisplayManagerGlobal { synchronized (mLock) { int index = findDisplayListenerLocked(listener); if (index < 0) { Looper looper = getLooperForHandler(handler); mDisplayListeners.add(new DisplayListenerDelegate(listener, looper, eventsMask)); mDisplayListeners.add(new DisplayListenerDelegate(listener, executor, eventsMask)); registerCallbackIfNeededLocked(); } else { mDisplayListeners.get(index).setEventsMask(eventsMask); Loading Loading @@ -408,6 +425,7 @@ public final class DisplayManagerGlobal { } private void handleDisplayEvent(int displayId, @DisplayEvent int event) { final DisplayInfo info; synchronized (mLock) { if (USE_CACHE) { mDisplayInfoCache.remove(displayId); Loading @@ -417,11 +435,7 @@ public final class DisplayManagerGlobal { } } final int numListeners = mDisplayListeners.size(); DisplayInfo info = getDisplayInfo(displayId); for (int i = 0; i < numListeners; i++) { mDisplayListeners.get(i).sendDisplayEvent(displayId, event, info); } info = getDisplayInfoLocked(displayId); if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) { // Choreographer only supports a single display, so only dispatch refresh rate // changes for the default display. Loading @@ -438,6 +452,11 @@ public final class DisplayManagerGlobal { } } } // Accepting an Executor means the listener may be synchronously invoked, so we must // not be holding mLock when we do so for (DisplayListenerDelegate listener : mDisplayListeners) { listener.sendDisplayEvent(displayId, event, info); } } public void startWifiDisplayScan() { Loading Loading @@ -1088,34 +1107,42 @@ public final class DisplayManagerGlobal { } } private static final class DisplayListenerDelegate extends Handler { private static final class DisplayListenerDelegate { public final DisplayListener mListener; public volatile long mEventsMask; private final DisplayInfo mDisplayInfo = new DisplayInfo(); private final Executor mExecutor; private AtomicLong mGenerationId = new AtomicLong(1); DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper, DisplayListenerDelegate(DisplayListener listener, @NonNull Executor executor, @EventsMask long eventsMask) { super(looper, null, true /*async*/); mExecutor = executor; mListener = listener; mEventsMask = eventsMask; } public void sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info) { Message msg = obtainMessage(event, displayId, 0, info); sendMessage(msg); long generationId = mGenerationId.get(); Message msg = Message.obtain(null, event, displayId, 0, info); mExecutor.execute(() -> { // If the generation id's don't match we were canceled but still need to recycle() if (generationId == mGenerationId.get()) { handleMessage(msg); } msg.recycle(); }); } public void clearEvents() { removeCallbacksAndMessages(null); mGenerationId.incrementAndGet(); } public void setEventsMask(@EventsMask long newEventsMask) { mEventsMask = newEventsMask; } @Override public void handleMessage(Message msg) { private void handleMessage(Message msg) { if (DEBUG) { Trace.beginSection( "DisplayListenerDelegate(" + eventToString(msg.what) Loading Loading @@ -1147,6 +1174,11 @@ public final class DisplayManagerGlobal { mListener.onDisplayRemoved(msg.arg1); } break; case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: if ((mEventsMask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) { mListener.onDisplayChanged(msg.arg1); } break; } if (DEBUG) { Trace.endSection(); Loading Loading @@ -1268,6 +1300,8 @@ public final class DisplayManagerGlobal { return "REMOVED"; case EVENT_DISPLAY_BRIGHTNESS_CHANGED: return "BRIGHTNESS_CHANGED"; case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: return "HDR_SDR_RATIO_CHANGED"; } return "UNKNOWN"; } Loading
core/java/android/view/Display.java +129 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * Provides information about the size and density of a logical display. Loading Loading @@ -111,6 +113,8 @@ public final class Display { private int mCachedAppWidthCompat; private int mCachedAppHeightCompat; private ArrayList<HdrSdrRatioListenerWrapper> mHdrSdrRatioListeners = new ArrayList<>(); /** * The default Display id, which is the id of the primary display assuming there is one. */ Loading Loading @@ -1291,6 +1295,102 @@ public final class Display { } } /** * @return Whether the display supports reporting an hdr/sdr ratio. If this is false, * {@link #getHdrSdrRatio()} will always be 1.0f * @hide * TODO: make public */ public boolean isHdrSdrRatioAvailable() { synchronized (mLock) { updateDisplayInfoLocked(); return !Float.isNaN(mDisplayInfo.hdrSdrRatio); } } /** * @return The current hdr/sdr ratio expressed as the ratio of targetHdrPeakBrightnessInNits / * targetSdrWhitePointInNits. If {@link #isHdrSdrRatioAvailable()} is false, this * always returns 1.0f. * * @hide * TODO: make public */ public float getHdrSdrRatio() { synchronized (mLock) { updateDisplayInfoLocked(); return Float.isNaN(mDisplayInfo.hdrSdrRatio) ? 1.0f : mDisplayInfo.hdrSdrRatio; } } private int findHdrSdrRatioListenerLocked(Consumer<Display> listener) { for (int i = 0; i < mHdrSdrRatioListeners.size(); i++) { final HdrSdrRatioListenerWrapper wrapper = mHdrSdrRatioListeners.get(i); if (wrapper.mListener == listener) { return i; } } return -1; } /** * Registers a listener that will be invoked whenever the display's hdr/sdr ratio has changed. * After receiving the callback on the specified Executor, call {@link #getHdrSdrRatio()} to * get the updated value. * If {@link #isHdrSdrRatioAvailable()} is false, then an IllegalStateException will be thrown * * @see #unregisterHdrSdrRatioChangedListener(Consumer) * @param executor The executor to invoke the listener on * @param listener The listener to invoke when the HDR/SDR ratio changes * @throws IllegalStateException if {@link #isHdrSdrRatioAvailable()} is false * @hide * TODO: Make public */ public void registerHdrSdrRatioChangedListener(@NonNull Executor executor, @NonNull Consumer<Display> listener) { if (!isHdrSdrRatioAvailable()) { throw new IllegalStateException("HDR/SDR ratio changed not available"); } HdrSdrRatioListenerWrapper toRegister = null; synchronized (mLock) { if (findHdrSdrRatioListenerLocked(listener) == -1) { toRegister = new HdrSdrRatioListenerWrapper(listener); mHdrSdrRatioListeners.add(toRegister); } // else already listening, don't do anything } if (toRegister != null) { // Although we only care about the HDR/SDR ratio changing, that can also come in the // form of the larger DISPLAY_CHANGED event mGlobal.registerDisplayListener(toRegister, executor, DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED | DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); } } /** * @param listener The previously * {@link #registerHdrSdrRatioChangedListener(Executor, Consumer) registered} * hdr/sdr ratio listener to remove. * * @see #registerHdrSdrRatioChangedListener(Executor, Consumer) * @hide * TODO: Make public */ public void unregisterHdrSdrRatioChangedListener(Consumer<Display> listener) { HdrSdrRatioListenerWrapper toRemove = null; synchronized (mLock) { int index = findHdrSdrRatioListenerLocked(listener); if (index != -1) { toRemove = mHdrSdrRatioListeners.remove(index); } } if (toRemove != null) { mGlobal.unregisterDisplayListener(toRemove); } } /** * Sets the default {@link Display.Mode} to use for the display. The display mode includes * preference for resolution and refresh rate. Loading Loading @@ -2528,4 +2628,33 @@ public final class Display { } } } private class HdrSdrRatioListenerWrapper implements DisplayManager.DisplayListener { Consumer<Display> mListener; float mLastReportedRatio = 1.f; private HdrSdrRatioListenerWrapper(Consumer<Display> listener) { mListener = listener; } @Override public void onDisplayAdded(int displayId) { // don't care } @Override public void onDisplayRemoved(int displayId) { // don't care } @Override public void onDisplayChanged(int displayId) { if (displayId == getDisplayId()) { float newRatio = getHdrSdrRatio(); if (newRatio != mLastReportedRatio) { mListener.accept(Display.this); } } } } }
core/java/android/view/DisplayInfo.java +20 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,8 @@ import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.proto.ProtoOutputStream; import com.android.internal.display.BrightnessSynchronizer; import java.util.Arrays; import java.util.Objects; Loading Loading @@ -340,6 +342,13 @@ public final class DisplayInfo implements Parcelable { @Nullable public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate; /** * The current hdr/sdr ratio for the display. If the display doesn't support hdr/sdr ratio * queries then this is NaN */ public float hdrSdrRatio = Float.NaN; public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() { @Override public DisplayInfo createFromParcel(Parcel source) { Loading Loading @@ -415,7 +424,8 @@ public final class DisplayInfo implements Parcelable { && Objects.equals(roundedCorners, other.roundedCorners) && installOrientation == other.installOrientation && Objects.equals(displayShape, other.displayShape) && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate); && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate) && BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio); } @Override Loading Loading @@ -471,6 +481,7 @@ public final class DisplayInfo implements Parcelable { installOrientation = other.installOrientation; displayShape = other.displayShape; layoutLimitedRefreshRate = other.layoutLimitedRefreshRate; hdrSdrRatio = other.hdrSdrRatio; } public void readFromParcel(Parcel source) { Loading Loading @@ -532,6 +543,7 @@ public final class DisplayInfo implements Parcelable { installOrientation = source.readInt(); displayShape = source.readTypedObject(DisplayShape.CREATOR); layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR); hdrSdrRatio = source.readFloat(); } @Override Loading Loading @@ -591,6 +603,7 @@ public final class DisplayInfo implements Parcelable { dest.writeInt(installOrientation); dest.writeTypedObject(displayShape, flags); dest.writeTypedObject(layoutLimitedRefreshRate, flags); dest.writeFloat(hdrSdrRatio); } @Override Loading Loading @@ -852,6 +865,12 @@ public final class DisplayInfo implements Parcelable { sb.append(Surface.rotationToString(installOrientation)); sb.append(", layoutLimitedRefreshRate "); sb.append(layoutLimitedRefreshRate); sb.append(", hdrSdrRatio "); if (Float.isNaN(hdrSdrRatio)) { sb.append("not_available"); } else { sb.append(hdrSdrRatio); } sb.append("}"); return sb.toString(); } Loading
services/core/java/com/android/server/display/DisplayDeviceConfig.java +2 −2 Original line number Diff line number Diff line Loading @@ -450,7 +450,7 @@ public class DisplayDeviceConfig { // so -2 is used instead private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f; private static final float NITS_INVALID = -1; static final float NITS_INVALID = -1; // Length of the ambient light horizon used to calculate the long term estimate of ambient // light. Loading Loading @@ -840,7 +840,7 @@ public class DisplayDeviceConfig { /** * Calculates the nits value for the specified backlight value if a mapping exists. * * @return The mapped nits or 0 if no mapping exits. * @return The mapped nits or {@link #NITS_INVALID} if no mapping exits. */ public float getNitsFromBacklight(float backlight) { if (mBacklightToNitsSpline == null) { Loading