From a9f63583d017dc10a3a0d2daa3c0e5219a3d686b Mon Sep 17 00:00:00 2001 From: Sean Stout Date: Mon, 26 Oct 2020 23:10:03 -0700 Subject: [PATCH] Introduce DisplayGroup A DisplayGroup is a collection of LogicalDisplays which are tied together for certain behaviors and operations. This CL simply introduces the class, however in the future it will be used for multi-display power state work. Bug: 138328918 Test: manual - build and deploy Change-Id: I3d736b2758a3363678afc962872fcbe7f4e96806 --- .../hardware/display/DisplayManager.java | 9 +++++ core/java/android/view/Display.java | 9 +++++ .../server/display/DisplayDeviceInfo.java | 8 ++++ .../android/server/display/DisplayGroup.java | 39 +++++++++++++++++++ .../server/display/DisplayManagerService.java | 12 ++++++ .../server/display/LogicalDisplay.java | 3 ++ .../server/display/LogicalDisplayMapper.java | 36 +++++++++++++++++ .../server/display/VirtualDisplayAdapter.java | 6 +++ 8 files changed, 122 insertions(+) create mode 100644 services/core/java/com/android/server/display/DisplayGroup.java diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 68b9d52277461..d6cd3feafca72 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -326,6 +326,15 @@ public final class DisplayManager { @TestApi public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10; + /** + * Virtual display flags: Indicates that the display should not be a part of the default + * DisplayGroup and instead be part of a new DisplayGroup. + * + * @see #createVirtualDisplay + * @hide + */ + public static final int VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP = 1 << 11; + /** @hide */ public DisplayManager(Context context) { mContext = context; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 34e8221bc9714..ab76e4aea993a 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -261,6 +261,15 @@ public final class Display { @TestApi public static final int FLAG_TRUSTED = 1 << 7; + /** + * Flag: Indicates that the display should not be a part of the default DisplayGroup and + * instead be part of a new DisplayGroup. + * + * @hide + * @see #getFlags() + */ + public static final int FLAG_OWN_DISPLAY_GROUP = 1 << 8; + /** * Display flag: Indicates that the contents of the display should not be scaled * to fit the physical screen dimensions. Used for development only to emulate diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index d4377e4870a53..fe6500e8942c2 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -129,6 +129,14 @@ final class DisplayDeviceInfo { */ public static final int FLAG_TRUSTED = 1 << 13; + /** + * Flag: Indicates that the display should not be a part of the default {@link DisplayGroup} and + * instead be part of a new {@link DisplayGroup}. + * + * @hide + */ + public static final int FLAG_OWN_DISPLAY_GROUP = 1 << 14; + /** * Touch attachment: Display does not receive touch. */ diff --git a/services/core/java/com/android/server/display/DisplayGroup.java b/services/core/java/com/android/server/display/DisplayGroup.java new file mode 100644 index 0000000000000..f2413edd1a3a6 --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayGroup.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 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 com.android.server.display; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a collection of {@link LogicalDisplay}s which act in unison for certain behaviors and + * operations. + */ +public class DisplayGroup { + + final List mDisplays = new ArrayList<>(); + + void addDisplay(LogicalDisplay display) { + if (!mDisplays.contains(display)) { + mDisplays.add(display); + } + } + + boolean removeDisplay(LogicalDisplay display) { + return mDisplays.remove(display); + } +} diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 60c83905ed9c0..c4dfcf5c3165f 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; @@ -2024,6 +2025,9 @@ public final class DisplayManagerService extends SystemService { if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; } + if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { + flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; + } if (projection != null) { try { @@ -2062,6 +2066,14 @@ public final class DisplayManagerService extends SystemService { } } + if (callingUid != Process.SYSTEM_UID + && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { + if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { + throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + + "create a virtual display which is not in the default DisplayGroup."); + } + } + if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index a17a294cd1d74..e35becc93be06 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -280,6 +280,9 @@ final class LogicalDisplay { if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TRUSTED) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_TRUSTED; } + if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) { + mBaseDisplayInfo.flags |= Display.FLAG_OWN_DISPLAY_GROUP; + } Rect maskingInsets = getMaskingInsets(deviceInfo); int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right; int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom; diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index fc3ba35c52ba4..a843af5982b4b 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -35,6 +35,9 @@ import java.util.function.Consumer; * Responsible for creating {@link LogicalDisplay}s and associating them to the * {@link DisplayDevice} objects supplied through {@link DisplayAdapter.Listener}. * + * Additionally this class will keep track of which {@link DisplayGroup} each + * {@link LogicalDisplay} belongs to. + * * For devices with a single internal display, the mapping is done once and left * alone. For devices with multiple built-in displays, such as foldable devices, * {@link LogicalDisplay}s can be remapped to different {@link DisplayDevice}s. @@ -91,6 +94,9 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { new SparseArray(); private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1; + /** A mapping from logical display id to display group. */ + private final SparseArray mDisplayGroups = new SparseArray<>(); + private final DisplayDeviceRepository mDisplayDeviceRepo; private final PersistentDataStore mPersistentDataStore; private final Listener mListener; @@ -296,6 +302,15 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { mLogicalDisplays.put(displayId, display); + final DisplayGroup displayGroup; + if (isDefault || (deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) { + displayGroup = new DisplayGroup(); + } else { + displayGroup = mDisplayGroups.get(Display.DEFAULT_DISPLAY); + } + displayGroup.addDisplay(display); + mDisplayGroups.append(displayId, displayGroup); + mListener.onLogicalDisplayEventLocked(display, LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED); } @@ -314,10 +329,31 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { display.updateLocked(mDisplayDeviceRepo); if (!display.isValidLocked()) { mLogicalDisplays.removeAt(i); + mDisplayGroups.removeReturnOld(displayId).removeDisplay(display); mListener.onLogicalDisplayEventLocked(display, LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED); } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { + final int flags = display.getDisplayInfoLocked().flags; + final DisplayGroup defaultDisplayGroup = mDisplayGroups.get( + Display.DEFAULT_DISPLAY); + if ((flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0) { + // The display should have its own DisplayGroup. + if (defaultDisplayGroup.removeDisplay(display)) { + final DisplayGroup displayGroup = new DisplayGroup(); + displayGroup.addDisplay(display); + mDisplayGroups.append(display.getDisplayIdLocked(), displayGroup); + } + } else { + // The display should be a part of the default DisplayGroup. + final DisplayGroup displayGroup = mDisplayGroups.get(displayId); + if (displayGroup != defaultDisplayGroup) { + displayGroup.removeDisplay(display); + defaultDisplayGroup.addDisplay(display); + mDisplayGroups.put(displayId, defaultDisplayGroup); + } + } + final String oldUniqueId = mTempDisplayInfo.uniqueId; final String newUniqueId = display.getDisplayInfoLocked().uniqueId; final int eventMsg = TextUtils.equals(oldUniqueId, newUniqueId) diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 210d2979c8072..ff4717b7131b5 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -19,6 +19,7 @@ package com.android.server.display; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT; @@ -27,6 +28,7 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOUL import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; +import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; import android.content.Context; @@ -386,6 +388,10 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK; } else { mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; + + if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { + mInfo.flags |= FLAG_OWN_DISPLAY_GROUP; + } } if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {