From 4f67ba6ba4e861b287a3ff0323c107aa77f66264 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Thu, 2 Aug 2012 11:23:00 -0700 Subject: [PATCH] Refactor DisplayManagerService to be functional. Change-Id: Ieac1eca172be5dc5db45302d3afa26188acd4d6d --- core/java/android/view/Display.java | 6 + .../com/android/server/display/DisplayAdapter.java | 22 +- .../server/display/DisplayManagerService.java | 257 ++++++++++++++++----- .../server/display/HeadlessDisplayAdapter.java | 4 +- .../display/SurfaceFlingerDisplayAdapter.java | 4 +- .../java/com/android/server/wm/DisplayContent.java | 7 +- .../android/server/wm/WindowManagerService.java | 53 +++-- 7 files changed, 264 insertions(+), 89 deletions(-) diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 6fd5b01ad311..b0ad4391a851 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -73,6 +73,12 @@ public final class Display { public static final int DEFAULT_DISPLAY = 0; /** + * Uninitialized display. + * @hide + */ + public static final int NO_DISPLAY = -1; + + /** * Internal method to create a display. * Applications should use {@link android.view.WindowManager#getDefaultDisplay()} * to get a display object for the default display. diff --git a/services/java/com/android/server/display/DisplayAdapter.java b/services/java/com/android/server/display/DisplayAdapter.java index e150bf8adf02..b6239061eabc 100644 --- a/services/java/com/android/server/display/DisplayAdapter.java +++ b/services/java/com/android/server/display/DisplayAdapter.java @@ -16,14 +16,32 @@ package com.android.server.display; +import android.view.Display; + /** - * A display adapter makes one or more display devices available to the system. + * A display adapter makes a single display devices available to the system. *

* For now, all display adapters are registered in the system server but * in principle it could be done from other processes. *

*/ public abstract class DisplayAdapter { + /** The current logical Display assignment for this adapter. Will change if other logical + * display is assigned to this adapter */ + private int mDisplayId = Display.NO_DISPLAY; + + /** Assign the displayId + * @hide */ + public void setDisplayId(int displayId) { + mDisplayId = displayId; + } + + /** Retrieve the displayId + * @hide */ + public int getDisplayId() { + return mDisplayId; + } + /** * Gets the display adapter name. * @return The display adapter name. @@ -31,5 +49,5 @@ public abstract class DisplayAdapter { public abstract String getName(); // TODO: dynamically register display devices - public abstract DisplayDevice[] getDisplayDevices(); + public abstract DisplayDevice getDisplayDevice(); } diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java index e71406434219..b9c9ffde91aa 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -22,6 +22,8 @@ import android.content.pm.PackageManager; import android.hardware.display.IDisplayManager; import android.os.Binder; import android.os.SystemProperties; +import android.util.Slog; +import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; @@ -47,28 +49,34 @@ public final class DisplayManagerService extends IDisplayManager.Stub { private Context mContext; private final boolean mHeadless; + + private int mDisplayIdSeq = Display.DEFAULT_DISPLAY; + + /** All registered DisplayAdapters. */ private final ArrayList mDisplayAdapters = new ArrayList(); - // TODO: represent this as a map between logical and physical devices - private DisplayInfo mDefaultDisplayInfo; - private DisplayDevice mDefaultDisplayDevice; - private DisplayDeviceInfo mDefaultDisplayDeviceInfo; + /** All the DisplayAdapters showing the given displayId. */ + private final SparseArray> mLogicalToPhysicals = + new SparseArray>(); + + /** All the DisplayInfos in the system indexed by deviceId */ + private final SparseArray mDisplayInfos = new SparseArray(); public DisplayManagerService() { mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1"); - registerDisplayAdapters(); - initializeDefaultDisplay(); + registerDefaultDisplayAdapter(); } - public void setContext(Context context) { - mContext = context; + private void registerDefaultDisplayAdapter() { + if (mHeadless) { + registerDisplayAdapter(new HeadlessDisplayAdapter()); + } else { + registerDisplayAdapter(new SurfaceFlingerDisplayAdapter()); + } } - // FIXME: this isn't the right API for the long term - public void setDefaultDisplayInfo(DisplayInfo info) { - synchronized (mLock) { - mDefaultDisplayInfo.copyFrom(info); - } + public void setContext(Context context) { + mContext = context; } // FIXME: this isn't the right API for the long term @@ -83,17 +91,187 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return mHeadless; } + /** + * Save away new DisplayInfo data. + * @param displayId The local DisplayInfo to store the new data in. + * @param info The new data to be stored. + */ + public void setDisplayInfo(int displayId, DisplayInfo info) { + synchronized (mLock) { + DisplayInfo localInfo = mDisplayInfos.get(displayId); + if (localInfo == null) { + localInfo = new DisplayInfo(); + mDisplayInfos.put(displayId, localInfo); + } + localInfo.copyFrom(info); + } + } + + /** + * Return requested DisplayInfo. + * @param displayId The data to retrieve. + * @param outInfo The structure to receive the data. + */ @Override // Binder call public boolean getDisplayInfo(int displayId, DisplayInfo outInfo) { synchronized (mLock) { - if (displayId == Display.DEFAULT_DISPLAY) { - outInfo.copyFrom(mDefaultDisplayInfo); - return true; + DisplayInfo localInfo = mDisplayInfos.get(displayId); + if (localInfo == null) { + return false; + } + outInfo.copyFrom(localInfo); + return true; + } + } + + /** + * Inform the service of a new physical display. A new logical displayId is created and the new + * physical display is immediately bound to it. Use removeAdapterFromDisplay to disconnect it. + * + * @param adapter The wrapper for information associated with the physical display. + */ + public void registerDisplayAdapter(DisplayAdapter adapter) { + synchronized (mLock) { + int displayId = mDisplayIdSeq++; + adapter.setDisplayId(displayId); + + createDisplayInfoLocked(displayId, adapter); + + ArrayList list = new ArrayList(); + list.add(adapter); + mLogicalToPhysicals.put(displayId, list); + + mDisplayAdapters.add(adapter); + } + + // TODO: Notify SurfaceFlinger of new addition. + } + + /** + * Connect a logical display to a physical display. Will remove the physical display from any + * logical display it is currently attached to. + * + * @param displayId The logical display. Will be created if it does not already exist. + * @param adapter The physical display. + */ + public void addAdapterToDisplay(int displayId, DisplayAdapter adapter) { + if (adapter == null) { + // TODO: Or throw NPE? + Slog.e(TAG, "addDeviceToDisplay: Attempt to add null adapter"); + return; + } + + synchronized (mLock) { + if (!mDisplayAdapters.contains(adapter)) { + // TOOD: Handle unregistered adapter with exception or return value. + Slog.e(TAG, "addDeviceToDisplay: Attempt to add an unregistered adapter"); + return; + } + + DisplayInfo displayInfo = mDisplayInfos.get(displayId); + if (displayInfo == null) { + createDisplayInfoLocked(displayId, adapter); + } + + Integer oldDisplayId = adapter.getDisplayId(); + if (oldDisplayId != Display.NO_DISPLAY) { + if (oldDisplayId == displayId) { + // adapter already added to displayId. + return; + } + + removeAdapterLocked(adapter); + } + + ArrayList list = mLogicalToPhysicals.get(displayId); + if (list == null) { + list = new ArrayList(); + mLogicalToPhysicals.put(displayId, list); + } + + list.add(adapter); + adapter.setDisplayId(displayId); + } + + // TODO: Notify SurfaceFlinger of new addition. + } + + /** + * Disconnect the physical display from whichever logical display it is attached to. + * @param adapter The physical display to detach. + */ + public void removeAdapterFromDisplay(DisplayAdapter adapter) { + if (adapter == null) { + // TODO: Or throw NPE? + return; + } + + synchronized (mLock) { + if (!mDisplayAdapters.contains(adapter)) { + // TOOD: Handle unregistered adapter with exception or return value. + Slog.e(TAG, "removeDeviceFromDisplay: Attempt to remove an unregistered adapter"); + return; + } + + removeAdapterLocked(adapter); + } + + // TODO: Notify SurfaceFlinger of removal. + } + + /** + * Create a new logical DisplayInfo and fill it in with information from the physical display. + * @param displayId The logical identifier. + * @param adapter The physical display for initial values. + */ + private void createDisplayInfoLocked(int displayId, DisplayAdapter adapter) { + DisplayInfo displayInfo = new DisplayInfo(); + DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo(); + adapter.getDisplayDevice().getInfo(deviceInfo); + copyDisplayInfoFromDeviceInfo(displayInfo, deviceInfo); + mDisplayInfos.put(displayId, displayInfo); + } + + /** + * Disconnect a physical display from its logical display. If there are no more physical + * displays attached to the logical display, delete the logical display. + * @param adapter The physical display to detach. + */ + void removeAdapterLocked(DisplayAdapter adapter) { + int displayId = adapter.getDisplayId(); + adapter.setDisplayId(Display.NO_DISPLAY); + + ArrayList list = mLogicalToPhysicals.get(displayId); + if (list != null) { + list.remove(adapter); + if (list.isEmpty()) { + mLogicalToPhysicals.remove(displayId); + // TODO: Keep count of Windows attached to logical display and don't delete if + // there are any outstanding. Also, what keeps the WindowManager from continuing + // to use the logical display? + mDisplayInfos.remove(displayId); } - return false; } } + private void copyDisplayInfoFromDeviceInfo(DisplayInfo displayInfo, + DisplayDeviceInfo deviceInfo) { + // Bootstrap the logical display using the physical display. + displayInfo.appWidth = deviceInfo.width; + displayInfo.appHeight = deviceInfo.height; + displayInfo.logicalWidth = deviceInfo.width; + displayInfo.logicalHeight = deviceInfo.height; + displayInfo.rotation = Surface.ROTATION_0; + displayInfo.refreshRate = deviceInfo.refreshRate; + displayInfo.logicalDensityDpi = deviceInfo.densityDpi; + displayInfo.physicalXDpi = deviceInfo.xDpi; + displayInfo.physicalYDpi = deviceInfo.yDpi; + displayInfo.smallestNominalAppWidth = deviceInfo.width; + displayInfo.smallestNominalAppHeight = deviceInfo.height; + displayInfo.largestNominalAppWidth = deviceInfo.width; + displayInfo.largestNominalAppHeight = deviceInfo.height; + } + @Override // Binder call public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext == null @@ -110,46 +288,11 @@ public final class DisplayManagerService extends IDisplayManager.Stub { DisplayDeviceInfo info = new DisplayDeviceInfo(); for (DisplayAdapter adapter : mDisplayAdapters) { - pw.println("Displays for adapter " + adapter.getName()); - for (DisplayDevice device : adapter.getDisplayDevices()) { - device.getInfo(info); - pw.print(" "); - pw.println(info); - } + pw.println("Display for adapter " + adapter.getName()); + DisplayDevice device = adapter.getDisplayDevice(); + pw.print(" "); + device.getInfo(info); + pw.println(info); } } - - private void registerDisplayAdapters() { - if (mHeadless) { - registerDisplayAdapter(new HeadlessDisplayAdapter()); - } else { - registerDisplayAdapter(new SurfaceFlingerDisplayAdapter()); - } - } - - private void registerDisplayAdapter(DisplayAdapter adapter) { - // TODO: do this dynamically - mDisplayAdapters.add(adapter); - mDefaultDisplayDevice = adapter.getDisplayDevices()[0]; - mDefaultDisplayDeviceInfo = new DisplayDeviceInfo(); - mDefaultDisplayDevice.getInfo(mDefaultDisplayDeviceInfo); - } - - private void initializeDefaultDisplay() { - // Bootstrap the default logical display using the default physical display. - mDefaultDisplayInfo = new DisplayInfo(); - mDefaultDisplayInfo.appWidth = mDefaultDisplayDeviceInfo.width; - mDefaultDisplayInfo.appHeight = mDefaultDisplayDeviceInfo.height; - mDefaultDisplayInfo.logicalWidth = mDefaultDisplayDeviceInfo.width; - mDefaultDisplayInfo.logicalHeight = mDefaultDisplayDeviceInfo.height; - mDefaultDisplayInfo.rotation = Surface.ROTATION_0; - mDefaultDisplayInfo.refreshRate = mDefaultDisplayDeviceInfo.refreshRate; - mDefaultDisplayInfo.logicalDensityDpi = mDefaultDisplayDeviceInfo.densityDpi; - mDefaultDisplayInfo.physicalXDpi = mDefaultDisplayDeviceInfo.xDpi; - mDefaultDisplayInfo.physicalYDpi = mDefaultDisplayDeviceInfo.yDpi; - mDefaultDisplayInfo.smallestNominalAppWidth = mDefaultDisplayDeviceInfo.width; - mDefaultDisplayInfo.smallestNominalAppHeight = mDefaultDisplayDeviceInfo.height; - mDefaultDisplayInfo.largestNominalAppWidth = mDefaultDisplayDeviceInfo.width; - mDefaultDisplayInfo.largestNominalAppHeight = mDefaultDisplayDeviceInfo.height; - } } diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java index cd18c374df52..3eaf40f9cec2 100644 --- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java +++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java @@ -40,7 +40,7 @@ public final class HeadlessDisplayAdapter extends DisplayAdapter { } @Override - public DisplayDevice[] getDisplayDevices() { - return new DisplayDevice[] { mDefaultDisplay }; + public DisplayDevice getDisplayDevice() { + return mDefaultDisplay; } } diff --git a/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java b/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java index 89934d3251b0..539f7c1dc3f6 100644 --- a/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java +++ b/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java @@ -35,7 +35,7 @@ public final class SurfaceFlingerDisplayAdapter extends DisplayAdapter { } @Override - public DisplayDevice[] getDisplayDevices() { - return new DisplayDevice[] { mDefaultDisplay }; + public DisplayDevice getDisplayDevice() { + return mDefaultDisplay; } } diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java index d4c17c562fb9..2305c8870a56 100644 --- a/services/java/com/android/server/wm/DisplayContent.java +++ b/services/java/com/android/server/wm/DisplayContent.java @@ -18,6 +18,8 @@ package com.android.server.wm; import android.view.DisplayInfo; +import com.android.server.display.DisplayManagerService; + import java.io.PrintWriter; import java.util.ArrayList; @@ -56,10 +58,13 @@ class DisplayContent { int mInitialDisplayHeight = 0; int mBaseDisplayWidth = 0; int mBaseDisplayHeight = 0; + final DisplayManagerService mDisplayManager; final DisplayInfo mDisplayInfo = new DisplayInfo(); - DisplayContent(final int displayId) { + DisplayContent(DisplayManagerService displayManager, final int displayId) { + mDisplayManager = displayManager; mDisplayId = displayId; + displayManager.getDisplayInfo(displayId, mDisplayInfo); } int getDisplayId() { diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 8b5c923c1b1a..e763a56d6fd4 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -4876,7 +4876,7 @@ public class WindowManagerService extends IWindowManager.Stub final int pos = findWindowOffsetLocked(windows, tokenPos); reAddAppWindowsLocked(displayContent, pos, wtoken); - if (updateFocusAndLayout && !updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, + if (updateFocusAndLayout && !updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/)) { assignLayersLocked(windows); } @@ -4927,7 +4927,7 @@ public class WindowManagerService extends IWindowManager.Stub mInputMonitor.setUpdateInputWindowsNeededLw(); - // Note that the above updateFocusedWindowLocked used to sit here. + // Note that the above updateFocusedWindowLocked used to sit here. mLayoutNeeded = true; performLayoutAndPlaceSurfacesLocked(); @@ -6572,7 +6572,7 @@ public class WindowManagerService extends IWindowManager.Stub displayInfo.appHeight = appHeight; displayInfo.getLogicalMetrics(mRealDisplayMetrics, null); displayInfo.getAppMetrics(mDisplayMetrics, null); - mDisplayManager.setDefaultDisplayInfo(displayInfo); + mDisplayManager.setDisplayInfo(displayContent.getDisplayId(), displayInfo); mAnimator.setDisplayDimensions(dw, dh, appWidth, appHeight); } @@ -6882,48 +6882,51 @@ public class WindowManagerService extends IWindowManager.Stub public void displayReady() { displayReady(Display.DEFAULT_DISPLAY); - } - public void displayReady(int displayId) { synchronized(mWindowMap) { - if (mDisplay != null) { - throw new IllegalStateException("Display already initialized"); - } WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); mDisplay = wm.getDefaultDisplay(); mIsTouchDevice = mContext.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_TOUCHSCREEN); + PackageManager.FEATURE_TOUCHSCREEN); + + final DisplayInfo displayInfo = getDefaultDisplayInfo(); + mAnimator.setDisplayDimensions(displayInfo.logicalWidth, displayInfo.logicalHeight, + displayInfo.appWidth, displayInfo.appHeight); + + DisplayDeviceInfo info = new DisplayDeviceInfo(); + mDisplayManager.getDefaultExternalDisplayDeviceInfo(info); + + final DisplayContent displayContent = getDefaultDisplayContent(); + mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY, + displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight, + info.width, info.height); + mInputManager.setDisplayOrientation(Display.DEFAULT_DISPLAY, + mDisplay.getRotation(), Surface.ROTATION_0); + mPolicy.setInitialDisplaySize(mDisplay, + displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight); + } + } + public void displayReady(int displayId) { + synchronized(mWindowMap) { final DisplayContent displayContent = getDisplayContent(displayId); + final DisplayInfo displayInfo; synchronized(displayContent.mDisplaySizeLock) { // Bootstrap the default logical display from the display manager. - final DisplayInfo displayInfo = displayContent.getDisplayInfo(); + displayInfo = displayContent.getDisplayInfo(); mDisplayManager.getDisplayInfo(displayId, displayInfo); displayContent.mInitialDisplayWidth = displayInfo.logicalWidth; displayContent.mInitialDisplayHeight = displayInfo.logicalHeight; displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth; displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight; - - mAnimator.setDisplayDimensions(displayInfo.logicalWidth, displayInfo.logicalHeight, - displayInfo.appWidth, displayInfo.appHeight); } - - DisplayDeviceInfo info = new DisplayDeviceInfo(); - mDisplayManager.getDefaultExternalDisplayDeviceInfo(info); - mInputManager.setDisplaySize(displayId, - displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight, - info.width, info.height); - mInputManager.setDisplayOrientation(displayId, - mDisplay.getRotation(), Surface.ROTATION_0); - mPolicy.setInitialDisplaySize(mDisplay, - displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight); } try { mActivityManager.updateConfiguration(null); } catch (RemoteException e) { } - + synchronized (mWindowMap) { readForcedDisplaySizeLocked(getDisplayContent(displayId)); } @@ -10325,7 +10328,7 @@ public class WindowManagerService extends IWindowManager.Stub public DisplayContent getDisplayContent(final int displayId) { DisplayContent displayContent = mDisplayContents.get(displayId); if (displayContent == null) { - displayContent = new DisplayContent(displayId); + displayContent = new DisplayContent(mDisplayManager, displayId); mDisplayContents.put(displayId, displayContent); } return displayContent; -- 2.11.0