Merge "Make mirroring automatic based on Windows on display." into jb-mr1-dev
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index ae958df..dc85d3f 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -58,7 +58,7 @@
* </p><p>
* Display adapters are only weakly coupled to the display manager service.
* Display adapters communicate changes in display device state to the display manager
- * service asynchronously via a {@link DisplayAdapter.DisplayAdapterListener} registered
+ * service asynchronously via a {@link DisplayAdapter.Listener} registered
* by the display manager service. This separation of concerns is important for
* two main reasons. First, it neatly encapsulates the responsibilities of these
* two classes: display adapters handle individual display devices whereas
@@ -254,8 +254,8 @@
* Returns information about the specified logical display.
*
* @param displayId The logical display id.
- * @param The logical display info, or null if the display does not exist.
- * This object must be treated as immutable.
+ * @return The logical display info, or null if the display does not exist. The
+ * returned object must be treated as immutable.
*/
@Override // Binder call
public DisplayInfo getDisplayInfo(int displayId) {
@@ -481,14 +481,34 @@
}
}
- private void configureDisplayInTransactionLocked(DisplayDevice device) {
- // TODO: add a proper per-display mirroring control
- boolean isMirroring = SystemProperties.getBoolean("debug.display.mirror", true);
+ /**
+ * Tells the display manager whether there is interesting unique content on the
+ * specified logical display. This is used to control automatic mirroring.
+ * <p>
+ * If the display has unique content, then the display manager arranges for it
+ * to be presented on a physical display if appropriate. Otherwise, the display manager
+ * may choose to make the physical display mirror some other logical display.
+ * </p>
+ *
+ * @param displayId The logical display id to update.
+ * @param hasContent True if the logical display has content.
+ */
+ public void setDisplayHasContent(int displayId, boolean hasContent) {
+ synchronized (mSyncRoot) {
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null && display.hasContentLocked() != hasContent) {
+ display.setHasContentLocked(hasContent);
+ scheduleTraversalLocked();
+ }
+ }
+ }
+
+ private void configureDisplayInTransactionLocked(DisplayDevice device) {
// Find the logical display that the display device is showing.
- LogicalDisplay display = null;
- if (!isMirroring) {
- display = findLogicalDisplayForDeviceLocked(device);
+ LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
+ if (display != null && !display.hasContentLocked()) {
+ display = null;
}
if (display == null) {
display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
@@ -611,8 +631,9 @@
*/
public interface WindowManagerFuncs {
/**
- * Request that the window manager call {@link #performTraversalInTransaction}
- * within a surface transaction at a later time.
+ * Request that the window manager call
+ * {@link #performTraversalInTransactionFromWindowManager} within a surface
+ * transaction at a later time.
*/
void requestTraversal();
}
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index c864189..e0f63dd 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -63,6 +63,9 @@
private DisplayDevice mPrimaryDisplayDevice;
private DisplayDeviceInfo mPrimaryDisplayDeviceInfo;
+ // True if the logical display has unique content.
+ private boolean mHasContent;
+
// Temporary rectangle used when needed.
private final Rect mTempLayerStackRect = new Rect();
private final Rect mTempDisplayRect = new Rect();
@@ -126,7 +129,7 @@
/**
* Returns true if the logical display is in a valid state.
- * This method should be checked after calling {@link #update} to handle the
+ * This method should be checked after calling {@link #updateLocked} to handle the
* case where a logical display should be removed because all of its associated
* display devices are gone or if it is otherwise no longer needed.
*
@@ -256,6 +259,29 @@
device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
}
+ /**
+ * Returns true if the logical display has unique content.
+ * <p>
+ * If the display has unique content then we will try to ensure that it is
+ * visible on at least its primary display device. Otherwise we will ignore the
+ * logical display and perhaps show mirrored content on the primary display device.
+ * </p>
+ *
+ * @return True if the display has unique content.
+ */
+ public boolean hasContentLocked() {
+ return mHasContent;
+ }
+
+ /**
+ * Sets whether the logical display has unique content.
+ *
+ * @param hasContent True if the display has unique content.
+ */
+ public void setHasContentLocked(boolean hasContent) {
+ mHasContent = hasContent;
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println("mLayerStack=" + mLayerStack);
pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 0ea051f..4df692b 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -94,10 +94,13 @@
}
DisplayInfo getDisplayInfo() {
- // TODO: Add a listener for changes to Display and update mDisplayInfo when appropriate.
return mDisplayInfo;
}
+ public void updateDisplayInfo() {
+ mDisplay.getDisplayInfo(mDisplayInfo);
+ }
+
public void dump(PrintWriter pw) {
pw.print(" Display: mDisplayId="); pw.println(mDisplayId);
pw.print(" init="); pw.print(mInitialDisplayWidth); pw.print("x");
@@ -121,7 +124,7 @@
pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
pw.print(" layoutNeeded="); pw.println(layoutNeeded);
- pw.print("magnificationSpec="); pw.println(mMagnificationSpec.toString());
+ pw.print("magnificationSpec="); pw.println(mMagnificationSpec);
pw.println();
}
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index a668efb..18e793d 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -165,7 +165,7 @@
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
- DisplayManagerService.WindowManagerFuncs {
+ DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
@@ -782,9 +782,15 @@
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
mDisplayManagerService = displayManager;
- mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mHeadless = displayManager.isHeadless();
+ mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+ mDisplayManager.registerDisplayListener(this, null);
+ Display[] displays = mDisplayManager.getDisplays();
+ for (Display display : displays) {
+ createDisplayContent(display);
+ }
+
mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
mPowerManager = pm;
@@ -1120,6 +1126,10 @@
if (win.mAppToken != null && addToToken) {
win.mAppToken.allAppWindows.add(win);
}
+
+ if (windows.size() == 1) {
+ mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), true);
+ }
}
/** TODO(cmautner): Is this the same as {@link WindowState#canReceiveKeys()} */
@@ -2408,6 +2418,9 @@
final WindowList windows = win.getWindowList();
windows.remove(win);
+ if (windows.isEmpty()) {
+ mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), false);
+ }
mPendingRemove.remove(win);
mWindowsChanged = true;
if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
@@ -7194,6 +7207,10 @@
public static final int NOTIFY_WINDOW_TRANSITION = 29;
public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30;
+ public static final int DO_DISPLAY_ADDED = 31;
+ public static final int DO_DISPLAY_REMOVED = 32;
+ public static final int DO_DISPLAY_CHANGED = 33;
+
public static final int ANIMATOR_WHAT_OFFSET = 100000;
public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
@@ -7631,18 +7648,21 @@
}
break;
}
+
case NOTIFY_ROTATION_CHANGED: {
final int displayId = msg.arg1;
final int rotation = msg.arg2;
handleNotifyRotationChanged(displayId, rotation);
break;
}
+
case NOTIFY_WINDOW_TRANSITION: {
final int transition = msg.arg1;
WindowInfo info = (WindowInfo) msg.obj;
handleNotifyWindowTranstion(transition, info);
break;
}
+
case NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
final int displayId = msg.arg1;
final boolean immediate = (msg.arg2 == 1);
@@ -7650,6 +7670,24 @@
handleNotifyRectangleOnScreenRequested(displayId, rectangle, immediate);
break;
}
+
+ case DO_DISPLAY_ADDED:
+ synchronized (mWindowMap) {
+ handleDisplayAddedLocked(msg.arg1);
+ }
+ break;
+
+ case DO_DISPLAY_REMOVED:
+ synchronized (mWindowMap) {
+ handleDisplayRemovedLocked(msg.arg1);
+ }
+ break;
+
+ case DO_DISPLAY_CHANGED:
+ synchronized (mWindowMap) {
+ handleDisplayChangedLocked(msg.arg1);
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG, "handleMessage: exit");
@@ -8866,8 +8904,6 @@
final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
final int defaultDw = defaultInfo.logicalWidth;
final int defaultDh = defaultInfo.logicalHeight;
- final int defaultInnerDw = defaultInfo.appWidth;
- final int defaultInnerDh = defaultInfo.appHeight;
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
@@ -9441,6 +9477,7 @@
}
}
+ @Override
public void requestTraversal() {
synchronized (mWindowMap) {
requestTraversalLocked();
@@ -10465,7 +10502,7 @@
boolean dumpWindows(PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll) {
- ArrayList<WindowState> windows = new ArrayList<WindowState>();
+ WindowList windows = new WindowList();
if ("visible".equals(name)) {
synchronized(mWindowMap) {
final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
@@ -10673,6 +10710,14 @@
}
}
+ public void createDisplayContent(final Display display) {
+ if (display == null) {
+ throw new IllegalArgumentException("getDisplayContent: display must not be null");
+ }
+ final DisplayContent displayContent = new DisplayContent(display);
+ mDisplayContents.put(display.getDisplayId(), displayContent);
+ }
+
public DisplayContent getDisplayContent(final int displayId) {
DisplayContent displayContent = mDisplayContents.get(displayId);
if (displayContent == null) {
@@ -10780,4 +10825,40 @@
public WindowList getWindowList(final Display display) {
return getDisplayContent(display.getDisplayId()).getWindowList();
}
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
+ }
+
+ private void handleDisplayAddedLocked(int displayId) {
+ createDisplayContent(mDisplayManager.getDisplay(displayId));
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
+ }
+
+ private void handleDisplayRemovedLocked(int displayId) {
+ final DisplayContent displayContent = getDisplayContent(displayId);
+ mDisplayContents.delete(displayId);
+ WindowList windows = displayContent.getWindowList();
+ for (int i = windows.size() - 1; i >= 0; --i) {
+ final WindowState win = windows.get(i);
+ removeWindowLocked(win.mSession, win);
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
+ }
+
+ private void handleDisplayChangedLocked(int displayId) {
+ final DisplayContent displayContent = getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.updateDisplayInfo();
+ }
+ }
}