Skip to content

Commit 722285e

Browse files
Craig MautnerJeff Brown
authored andcommitted
Make mirroring automatic based on Windows on display.
Tell the display manager whenever a given logical display contains interesting windows. If so, then the display manager arranges to show that content on a physical display, otherwise it ignores the logical display and makes its associated primary physical display mirror the default display. Assign DisplayContents when Displays are added, remove them when Displays are removed, and update the DisplayInfo when Displays change. Change-Id: I36e08ec538055acabe1e24cdd12c40de4e47a158
1 parent cbad976 commit 722285e

File tree

4 files changed

+150
-19
lines changed

4 files changed

+150
-19
lines changed

services/java/com/android/server/display/DisplayManagerService.java

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
* </p><p>
5959
* Display adapters are only weakly coupled to the display manager service.
6060
* Display adapters communicate changes in display device state to the display manager
61-
* service asynchronously via a {@link DisplayAdapter.DisplayAdapterListener} registered
61+
* service asynchronously via a {@link DisplayAdapter.Listener} registered
6262
* by the display manager service. This separation of concerns is important for
6363
* two main reasons. First, it neatly encapsulates the responsibilities of these
6464
* two classes: display adapters handle individual display devices whereas
@@ -254,8 +254,8 @@ public void performTraversalInTransactionFromWindowManager() {
254254
* Returns information about the specified logical display.
255255
*
256256
* @param displayId The logical display id.
257-
* @param The logical display info, or null if the display does not exist.
258-
* This object must be treated as immutable.
257+
* @return The logical display info, or null if the display does not exist. The
258+
* returned object must be treated as immutable.
259259
*/
260260
@Override // Binder call
261261
public DisplayInfo getDisplayInfo(int displayId) {
@@ -481,14 +481,34 @@ private void performTraversalInTransactionLocked() {
481481
}
482482
}
483483

484-
private void configureDisplayInTransactionLocked(DisplayDevice device) {
485-
// TODO: add a proper per-display mirroring control
486-
boolean isMirroring = SystemProperties.getBoolean("debug.display.mirror", true);
484+
/**
485+
* Tells the display manager whether there is interesting unique content on the
486+
* specified logical display. This is used to control automatic mirroring.
487+
* <p>
488+
* If the display has unique content, then the display manager arranges for it
489+
* to be presented on a physical display if appropriate. Otherwise, the display manager
490+
* may choose to make the physical display mirror some other logical display.
491+
* </p>
492+
*
493+
* @param displayId The logical display id to update.
494+
* @param hasContent True if the logical display has content.
495+
*/
496+
public void setDisplayHasContent(int displayId, boolean hasContent) {
497+
synchronized (mSyncRoot) {
498+
LogicalDisplay display = mLogicalDisplays.get(displayId);
499+
if (display != null && display.hasContentLocked() != hasContent) {
500+
display.setHasContentLocked(hasContent);
501+
scheduleTraversalLocked();
502+
}
503+
}
487504

505+
}
506+
507+
private void configureDisplayInTransactionLocked(DisplayDevice device) {
488508
// Find the logical display that the display device is showing.
489-
LogicalDisplay display = null;
490-
if (!isMirroring) {
491-
display = findLogicalDisplayForDeviceLocked(device);
509+
LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
510+
if (display != null && !display.hasContentLocked()) {
511+
display = null;
492512
}
493513
if (display == null) {
494514
display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
@@ -611,8 +631,9 @@ public static final class SyncRoot {
611631
*/
612632
public interface WindowManagerFuncs {
613633
/**
614-
* Request that the window manager call {@link #performTraversalInTransaction}
615-
* within a surface transaction at a later time.
634+
* Request that the window manager call
635+
* {@link #performTraversalInTransactionFromWindowManager} within a surface
636+
* transaction at a later time.
616637
*/
617638
void requestTraversal();
618639
}

services/java/com/android/server/display/LogicalDisplay.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ final class LogicalDisplay {
6363
private DisplayDevice mPrimaryDisplayDevice;
6464
private DisplayDeviceInfo mPrimaryDisplayDeviceInfo;
6565

66+
// True if the logical display has unique content.
67+
private boolean mHasContent;
68+
6669
// Temporary rectangle used when needed.
6770
private final Rect mTempLayerStackRect = new Rect();
6871
private final Rect mTempDisplayRect = new Rect();
@@ -126,7 +129,7 @@ public void setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
126129

127130
/**
128131
* Returns true if the logical display is in a valid state.
129-
* This method should be checked after calling {@link #update} to handle the
132+
* This method should be checked after calling {@link #updateLocked} to handle the
130133
* case where a logical display should be removed because all of its associated
131134
* display devices are gone or if it is otherwise no longer needed.
132135
*
@@ -256,6 +259,29 @@ public void configureDisplayInTransactionLocked(DisplayDevice device) {
256259
device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
257260
}
258261

262+
/**
263+
* Returns true if the logical display has unique content.
264+
* <p>
265+
* If the display has unique content then we will try to ensure that it is
266+
* visible on at least its primary display device. Otherwise we will ignore the
267+
* logical display and perhaps show mirrored content on the primary display device.
268+
* </p>
269+
*
270+
* @return True if the display has unique content.
271+
*/
272+
public boolean hasContentLocked() {
273+
return mHasContent;
274+
}
275+
276+
/**
277+
* Sets whether the logical display has unique content.
278+
*
279+
* @param hasContent True if the display has unique content.
280+
*/
281+
public void setHasContentLocked(boolean hasContent) {
282+
mHasContent = hasContent;
283+
}
284+
259285
public void dumpLocked(PrintWriter pw) {
260286
pw.println("mLayerStack=" + mLayerStack);
261287
pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?

services/java/com/android/server/wm/DisplayContent.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,13 @@ Display getDisplay() {
9494
}
9595

9696
DisplayInfo getDisplayInfo() {
97-
// TODO: Add a listener for changes to Display and update mDisplayInfo when appropriate.
9897
return mDisplayInfo;
9998
}
10099

100+
public void updateDisplayInfo() {
101+
mDisplay.getDisplayInfo(mDisplayInfo);
102+
}
103+
101104
public void dump(PrintWriter pw) {
102105
pw.print(" Display: mDisplayId="); pw.println(mDisplayId);
103106
pw.print(" init="); pw.print(mInitialDisplayWidth); pw.print("x");
@@ -121,7 +124,7 @@ public void dump(PrintWriter pw) {
121124
pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
122125
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
123126
pw.print(" layoutNeeded="); pw.println(layoutNeeded);
124-
pw.print("magnificationSpec="); pw.println(mMagnificationSpec.toString());
127+
pw.print("magnificationSpec="); pw.println(mMagnificationSpec);
125128
pw.println();
126129
}
127130
}

services/java/com/android/server/wm/WindowManagerService.java

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@
165165
/** {@hide} */
166166
public class WindowManagerService extends IWindowManager.Stub
167167
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
168-
DisplayManagerService.WindowManagerFuncs {
168+
DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener {
169169
static final String TAG = "WindowManager";
170170
static final boolean DEBUG = false;
171171
static final boolean DEBUG_ADD_REMOVE = false;
@@ -782,9 +782,15 @@ private WindowManagerService(Context context, PowerManagerService pm,
782782
mLimitedAlphaCompositing = context.getResources().getBoolean(
783783
com.android.internal.R.bool.config_sf_limitedAlpha);
784784
mDisplayManagerService = displayManager;
785-
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
786785
mHeadless = displayManager.isHeadless();
787786

787+
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
788+
mDisplayManager.registerDisplayListener(this, null);
789+
Display[] displays = mDisplayManager.getDisplays();
790+
for (Display display : displays) {
791+
createDisplayContent(display);
792+
}
793+
788794
mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
789795

790796
mPowerManager = pm;
@@ -1109,6 +1115,10 @@ private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
11091115
if (win.mAppToken != null && addToToken) {
11101116
win.mAppToken.allAppWindows.add(win);
11111117
}
1118+
1119+
if (windows.size() == 1) {
1120+
mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), true);
1121+
}
11121122
}
11131123

11141124
/** TODO(cmautner): Is this the same as {@link WindowState#canReceiveKeys()} */
@@ -2397,6 +2407,9 @@ private void removeWindowInnerLocked(Session session, WindowState win) {
23972407

23982408
final WindowList windows = win.getWindowList();
23992409
windows.remove(win);
2410+
if (windows.isEmpty()) {
2411+
mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), false);
2412+
}
24002413
mPendingRemove.remove(win);
24012414
mWindowsChanged = true;
24022415
if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
@@ -7183,6 +7196,10 @@ final class H extends Handler {
71837196
public static final int NOTIFY_WINDOW_TRANSITION = 29;
71847197
public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30;
71857198

7199+
public static final int DO_DISPLAY_ADDED = 31;
7200+
public static final int DO_DISPLAY_REMOVED = 32;
7201+
public static final int DO_DISPLAY_CHANGED = 33;
7202+
71867203
public static final int ANIMATOR_WHAT_OFFSET = 100000;
71877204
public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
71887205
public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
@@ -7620,25 +7637,46 @@ public void handleMessage(Message msg) {
76207637
}
76217638
break;
76227639
}
7640+
76237641
case NOTIFY_ROTATION_CHANGED: {
76247642
final int displayId = msg.arg1;
76257643
final int rotation = msg.arg2;
76267644
handleNotifyRotationChanged(displayId, rotation);
76277645
break;
76287646
}
7647+
76297648
case NOTIFY_WINDOW_TRANSITION: {
76307649
final int transition = msg.arg1;
76317650
WindowInfo info = (WindowInfo) msg.obj;
76327651
handleNotifyWindowTranstion(transition, info);
76337652
break;
76347653
}
7654+
76357655
case NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
76367656
final int displayId = msg.arg1;
76377657
final boolean immediate = (msg.arg2 == 1);
76387658
Rect rectangle = (Rect) msg.obj;
76397659
handleNotifyRectangleOnScreenRequested(displayId, rectangle, immediate);
76407660
break;
76417661
}
7662+
7663+
case DO_DISPLAY_ADDED:
7664+
synchronized (mWindowMap) {
7665+
handleDisplayAddedLocked(msg.arg1);
7666+
}
7667+
break;
7668+
7669+
case DO_DISPLAY_REMOVED:
7670+
synchronized (mWindowMap) {
7671+
handleDisplayRemovedLocked(msg.arg1);
7672+
}
7673+
break;
7674+
7675+
case DO_DISPLAY_CHANGED:
7676+
synchronized (mWindowMap) {
7677+
handleDisplayChangedLocked(msg.arg1);
7678+
}
7679+
break;
76427680
}
76437681
if (DEBUG_WINDOW_TRACE) {
76447682
Slog.v(TAG, "handleMessage: exit");
@@ -8855,8 +8893,6 @@ private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMe
88558893
final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
88568894
final int defaultDw = defaultInfo.logicalWidth;
88578895
final int defaultDh = defaultInfo.logicalHeight;
8858-
final int defaultInnerDw = defaultInfo.appWidth;
8859-
final int defaultInnerDh = defaultInfo.appHeight;
88608896

88618897
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
88628898
">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
@@ -9430,6 +9466,7 @@ void setHoldScreenLocked(final Session newHoldScreen) {
94309466
}
94319467
}
94329468

9469+
@Override
94339470
public void requestTraversal() {
94349471
synchronized (mWindowMap) {
94359472
requestTraversalLocked();
@@ -10454,7 +10491,7 @@ void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
1045410491

1045510492
boolean dumpWindows(PrintWriter pw, String name, String[] args,
1045610493
int opti, boolean dumpAll) {
10457-
ArrayList<WindowState> windows = new ArrayList<WindowState>();
10494+
WindowList windows = new WindowList();
1045810495
if ("visible".equals(name)) {
1045910496
synchronized(mWindowMap) {
1046010497
final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
@@ -10662,6 +10699,14 @@ void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
1066210699
}
1066310700
}
1066410701

10702+
public void createDisplayContent(final Display display) {
10703+
if (display == null) {
10704+
throw new IllegalArgumentException("getDisplayContent: display must not be null");
10705+
}
10706+
final DisplayContent displayContent = new DisplayContent(display);
10707+
mDisplayContents.put(display.getDisplayId(), displayContent);
10708+
}
10709+
1066510710
public DisplayContent getDisplayContent(final int displayId) {
1066610711
DisplayContent displayContent = mDisplayContents.get(displayId);
1066710712
if (displayContent == null) {
@@ -10769,4 +10814,40 @@ public DisplayInfo getDefaultDisplayInfo() {
1076910814
public WindowList getWindowList(final Display display) {
1077010815
return getDisplayContent(display.getDisplayId()).getWindowList();
1077110816
}
10817+
10818+
@Override
10819+
public void onDisplayAdded(int displayId) {
10820+
mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
10821+
}
10822+
10823+
private void handleDisplayAddedLocked(int displayId) {
10824+
createDisplayContent(mDisplayManager.getDisplay(displayId));
10825+
}
10826+
10827+
@Override
10828+
public void onDisplayRemoved(int displayId) {
10829+
mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
10830+
}
10831+
10832+
private void handleDisplayRemovedLocked(int displayId) {
10833+
final DisplayContent displayContent = getDisplayContent(displayId);
10834+
mDisplayContents.delete(displayId);
10835+
WindowList windows = displayContent.getWindowList();
10836+
for (int i = windows.size() - 1; i >= 0; --i) {
10837+
final WindowState win = windows.get(i);
10838+
removeWindowLocked(win.mSession, win);
10839+
}
10840+
}
10841+
10842+
@Override
10843+
public void onDisplayChanged(int displayId) {
10844+
mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
10845+
}
10846+
10847+
private void handleDisplayChangedLocked(int displayId) {
10848+
final DisplayContent displayContent = getDisplayContent(displayId);
10849+
if (displayContent != null) {
10850+
displayContent.updateDisplayInfo();
10851+
}
10852+
}
1077210853
}

0 commit comments

Comments
 (0)