summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/display/DisplayManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/display/DisplayManagerService.java')
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java534
1 files changed, 465 insertions, 69 deletions
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 1463780..cf835ef 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -16,52 +16,151 @@
package com.android.server.display;
+import com.android.internal.util.IndentingPrintWriter;
+
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.IDisplayManager;
+import android.hardware.display.IDisplayManagerCallback;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
+import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
/**
- * Manages the properties, media routing and power state of attached displays.
+ * Manages attached displays.
* <p>
- * The display manager service does not own or directly control the displays.
- * Instead, other components in the system register their display adapters with the
- * display manager service which acts as a central controller.
+ * The {@link DisplayManagerService} manages the global lifecycle of displays,
+ * decides how to configure logical displays based on the physical display devices currently
+ * attached, sends notifications to the system and to applications when the state
+ * changes, and so on.
+ * </p><p>
+ * The display manager service relies on a collection of {@link DisplayAdapter} components,
+ * for discovering and configuring physical display devices attached to the system.
+ * There are separate display adapters for each manner that devices are attached:
+ * one display adapter for built-in local displays, one for simulated non-functional
+ * displays when the system is headless, one for simulated overlay displays used for
+ * development, one for wifi displays, etc.
+ * </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
+ * 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
+ * the display manager service handles the global state. Second, it eliminates
+ * the potential for deadlocks resulting from asynchronous display device discovery.
+ * </p><p>
+ * To keep things simple, display adapters and display devices are single-threaded
+ * and are only accessed on the display manager's handler thread. Of course, the
+ * display manager must be accessible by multiple thread (especially for
+ * incoming binder calls) so all of the display manager's state is synchronized
+ * and guarded by a lock.
* </p>
*/
public final class DisplayManagerService extends IDisplayManager.Stub {
private static final String TAG = "DisplayManagerService";
+ private static final boolean DEBUG = false;
private static final String SYSTEM_HEADLESS = "ro.config.headless";
+ private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
+
+ private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1;
+ private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
+ private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
private final Object mLock = new Object();
private final Context mContext;
private final boolean mHeadless;
+ private final DisplayManagerHandler mHandler;
+ private final DisplayAdapterListener mDisplayAdapterListener = new DisplayAdapterListener();
+ private final SparseArray<CallbackRecord> mCallbacks =
+ new SparseArray<CallbackRecord>();
+
+ // List of all currently registered display adapters.
private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
- private final DisplayInfo mDefaultDisplayInfo = new DisplayInfo();
- private DisplayDevice mDefaultDisplayDevice;
- public DisplayManagerService(Context context) {
+ // List of all currently connected display devices.
+ private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
+
+ // List of all logical displays, indexed by logical display id.
+ private final SparseArray<LogicalDisplay> mLogicalDisplays = new SparseArray<LogicalDisplay>();
+ private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
+
+ // True if in safe mode.
+ // This option may disable certain display adapters.
+ private boolean mSafeMode;
+
+ // True if we are in a special boot mode where only core applications and
+ // services should be started. This option may disable certain display adapters.
+ private boolean mOnlyCore;
+
+ // Temporary callback list, used when sending display events to applications.
+ private ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
+
+ public DisplayManagerService(Context context, Handler uiHandler) {
mContext = context;
mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
- registerDefaultDisplayAdapter();
+ mHandler = new DisplayManagerHandler(uiHandler.getLooper());
+ mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
+ }
+
+ /**
+ * Pauses the boot process to wait for the first display to be initialized.
+ */
+ public boolean waitForDefaultDisplay() {
+ synchronized (mLock) {
+ long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
+ while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
+ long delay = timeout - SystemClock.uptimeMillis();
+ if (delay <= 0) {
+ return false;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
+ }
+ try {
+ mLock.wait(delay);
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Called when the system is ready to go.
+ */
+ public void systemReady(boolean safeMode, boolean onlyCore) {
+ synchronized (mLock) {
+ mSafeMode = safeMode;
+ mOnlyCore = onlyCore;
+ }
+ mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
}
+ // Runs on handler.
private void registerDefaultDisplayAdapter() {
+ // Register default display adapter.
if (mHeadless) {
registerDisplayAdapter(new HeadlessDisplayAdapter(mContext));
} else {
@@ -69,6 +168,34 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
}
+ // Runs on handler.
+ private void registerAdditionalDisplayAdapters() {
+ if (shouldRegisterNonEssentialDisplayAdapters()) {
+ registerDisplayAdapter(new OverlayDisplayAdapter(mContext));
+ }
+ }
+
+ private boolean shouldRegisterNonEssentialDisplayAdapters() {
+ // In safe mode, we disable non-essential display adapters to give the user
+ // an opportunity to fix broken settings or other problems that might affect
+ // system stability.
+ // In only-core mode, we disable non-essential display adapters to minimize
+ // the number of dependencies that are started while in this mode and to
+ // prevent problems that might occur due to the device being encrypted.
+ synchronized (mLock) {
+ return !mSafeMode && !mOnlyCore;
+ }
+ }
+
+ // Runs on handler.
+ private void registerDisplayAdapter(DisplayAdapter adapter) {
+ synchronized (mLock) {
+ mDisplayAdapters.add(adapter);
+ }
+
+ adapter.register(mDisplayAdapterListener);
+ }
+
// FIXME: this isn't the right API for the long term
public void getDefaultExternalDisplayDeviceInfo(DisplayDeviceInfo info) {
// hardcoded assuming 720p touch screen plugged into HDMI and USB
@@ -87,95 +214,224 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
/**
- * Set the new display orientation.
+ * Sets the new logical display orientation.
+ *
* @param displayId The logical display id.
* @param orientation One of the Surface.ROTATION_* constants.
*/
public void setDisplayOrientation(int displayId, int orientation) {
synchronized (mLock) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- throw new UnsupportedOperationException();
- }
-
- IBinder displayToken = mDefaultDisplayDevice.getDisplayToken();
- if (displayToken != null) {
- Surface.openTransaction();
- try {
- Surface.setDisplayOrientation(displayToken, orientation);
- } finally {
- Surface.closeTransaction();
+ // TODO: update mirror transforms
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null && display.mPrimaryDisplayDevice != null) {
+ IBinder displayToken = display.mPrimaryDisplayDevice.getDisplayToken();
+ if (displayToken != null) {
+ Surface.openTransaction();
+ try {
+ Surface.setDisplayOrientation(displayToken, orientation);
+ } finally {
+ Surface.closeTransaction();
+ }
}
+
+ display.mBaseDisplayInfo.rotation = orientation;
+ sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
}
}
}
/**
- * Save away new DisplayInfo data.
+ * Overrides the display information of a particular logical display.
+ * This is used by the window manager to control the size and characteristics
+ * of the default display.
+ *
* @param displayId The logical display id.
* @param info The new data to be stored.
*/
- public void setDisplayInfo(int displayId, DisplayInfo info) {
+ public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) {
synchronized (mLock) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- throw new UnsupportedOperationException();
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null) {
+ if (info != null) {
+ if (display.mOverrideDisplayInfo == null) {
+ display.mOverrideDisplayInfo = new DisplayInfo();
+ }
+ display.mOverrideDisplayInfo.copyFrom(info);
+ } else {
+ display.mOverrideDisplayInfo = null;
+ }
+
+ sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
}
- mDefaultDisplayInfo.copyFrom(info);
}
}
/**
- * Return requested DisplayInfo.
- * @param displayId The data to retrieve.
- * @param outInfo The structure to receive the data.
+ * 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.
*/
@Override // Binder call
- public boolean getDisplayInfo(int displayId, DisplayInfo outInfo) {
+ public DisplayInfo getDisplayInfo(int displayId) {
synchronized (mLock) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- return false;
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null) {
+ if (display.mOverrideDisplayInfo != null) {
+ return new DisplayInfo(display.mOverrideDisplayInfo);
+ }
+ return new DisplayInfo(display.mBaseDisplayInfo);
}
- outInfo.copyFrom(mDefaultDisplayInfo);
- return true;
+ return null;
}
}
- private void registerDisplayAdapter(DisplayAdapter adapter) {
- mDisplayAdapters.add(adapter);
- adapter.register(new DisplayAdapter.Listener() {
- @Override
- public void onDisplayDeviceAdded(DisplayDevice device) {
- mDefaultDisplayDevice = device;
- DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
- device.getInfo(deviceInfo);
- copyDisplayInfoFromDeviceInfo(mDefaultDisplayInfo, deviceInfo);
+ @Override // Binder call
+ public int[] getDisplayIds() {
+ synchronized (mLock) {
+ final int count = mLogicalDisplays.size();
+ int[] displayIds = new int[count];
+ for (int i = 0; i > count; i++) {
+ displayIds[i] = mLogicalDisplays.keyAt(i);
}
+ return displayIds;
+ }
+ }
- @Override
- public void onDisplayDeviceRemoved(DisplayDevice device) {
+ @Override // Binder call
+ public void registerCallback(IDisplayManagerCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ synchronized (mLock) {
+ int callingPid = Binder.getCallingPid();
+ if (mCallbacks.get(callingPid) != null) {
+ throw new SecurityException("The calling process has already "
+ + "registered an IDisplayManagerCallback.");
}
- });
+
+ CallbackRecord record = new CallbackRecord(callingPid, callback);
+ try {
+ IBinder binder = callback.asBinder();
+ binder.linkToDeath(record, 0);
+ } catch (RemoteException ex) {
+ // give up
+ throw new RuntimeException(ex);
+ }
+
+ mCallbacks.put(callingPid, record);
+ }
}
- 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;
+ private void onCallbackDied(int pid) {
+ synchronized (mLock) {
+ mCallbacks.remove(pid);
+ }
+ }
+
+ // Runs on handler.
+ private void handleDisplayDeviceAdded(DisplayDevice device) {
+ synchronized (mLock) {
+ if (mDisplayDevices.contains(device)) {
+ Slog.w(TAG, "Attempted to add already added display device: " + device);
+ return;
+ }
+
+ mDisplayDevices.add(device);
+
+ LogicalDisplay display = new LogicalDisplay(device);
+ display.updateFromPrimaryDisplayDevice();
+
+ boolean isDefault = (display.mPrimaryDisplayDeviceInfo.flags
+ & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
+ if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
+ Slog.w(TAG, "Attempted to add a second default device: " + device);
+ isDefault = false;
+ }
+
+ int displayId = isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
+ mLogicalDisplays.put(displayId, display);
+
+ sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
+
+ // Wake up waitForDefaultDisplay.
+ if (isDefault) {
+ mLock.notifyAll();
+ }
+ }
+ }
+
+ // Runs on handler.
+ private void handleDisplayDeviceChanged(DisplayDevice device) {
+ synchronized (mLock) {
+ if (!mDisplayDevices.contains(device)) {
+ Slog.w(TAG, "Attempted to change non-existent display device: " + device);
+ return;
+ }
+
+ for (int i = mLogicalDisplays.size(); i-- > 0; ) {
+ LogicalDisplay display = mLogicalDisplays.valueAt(i);
+ if (display.mPrimaryDisplayDevice == device) {
+ final int displayId = mLogicalDisplays.keyAt(i);
+ display.updateFromPrimaryDisplayDevice();
+ sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ }
+ }
+ }
+ }
+
+ // Runs on handler.
+ private void handleDisplayDeviceRemoved(DisplayDevice device) {
+ synchronized (mLock) {
+ if (!mDisplayDevices.remove(device)) {
+ Slog.w(TAG, "Attempted to remove non-existent display device: " + device);
+ return;
+ }
+
+ for (int i = mLogicalDisplays.size(); i-- > 0; ) {
+ LogicalDisplay display = mLogicalDisplays.valueAt(i);
+ if (display.mPrimaryDisplayDevice == device) {
+ final int displayId = mLogicalDisplays.keyAt(i);
+ mLogicalDisplays.removeAt(i);
+ sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
+ }
+ }
+ }
+ }
+
+ // Posts a message to send a display event at the next opportunity.
+ private void sendDisplayEventLocked(int displayId, int event) {
+ Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
+ mHandler.sendMessage(msg);
+ }
+
+ // Runs on handler.
+ // This method actually sends display event notifications.
+ // Note that it must be very careful not to be holding the lock while sending
+ // is in progress.
+ private void deliverDisplayEvent(int displayId, int event) {
+ if (DEBUG) {
+ Slog.d(TAG, "Delivering display event: displayId=" + displayId + ", event=" + event);
+ }
+
+ final int count;
+ synchronized (mLock) {
+ count = mCallbacks.size();
+ mTempCallbacks.clear();
+ for (int i = 0; i < count; i++) {
+ mTempCallbacks.add(mCallbacks.valueAt(i));
+ }
+ }
+
+ for (int i = 0; i < count; i++) {
+ mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
+ }
+ mTempCallbacks.clear();
}
@Override // Binder call
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (mContext == null
|| mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -184,19 +440,159 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
return;
}
- pw.println("DISPLAY MANAGER (dumpsys display)\n");
+ pw.println("DISPLAY MANAGER (dumpsys display)");
+ pw.println(" mHeadless=" + mHeadless);
- pw.println("Headless: " + mHeadless);
+ mHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ dumpLocal(pw);
+ }
+ });
+ }
+ // Runs on handler.
+ private void dumpLocal(PrintWriter pw) {
synchronized (mLock) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+
+ pw.println();
+ pw.println("Display Adapters: size=" + mDisplayAdapters.size());
for (DisplayAdapter adapter : mDisplayAdapters) {
- pw.println("Adapter: " + adapter.getName());
+ pw.println(" " + adapter.getName());
+ adapter.dump(ipw);
}
- pw.println("Default display info: " + mDefaultDisplayInfo);
+ pw.println();
+ pw.println("Display Devices: size=" + mDisplayDevices.size());
+ for (DisplayDevice device : mDisplayDevices) {
+ pw.println(" " + device);
+ }
+
+ final int logicalDisplayCount = mLogicalDisplays.size();
+ pw.println();
+ pw.println("Logical Displays: size=" + logicalDisplayCount);
+ for (int i = 0; i < logicalDisplayCount; i++) {
+ int displayId = mLogicalDisplays.keyAt(i);
+ LogicalDisplay display = mLogicalDisplays.valueAt(i);
+ pw.println(" Display " + displayId + ":");
+ pw.println(" mPrimaryDisplayDevice=" + display.mPrimaryDisplayDevice);
+ pw.println(" mBaseDisplayInfo=" + display.mBaseDisplayInfo);
+ pw.println(" mOverrideDisplayInfo="
+ + display.mOverrideDisplayInfo);
+ }
+ }
+ }
+
+ private final class DisplayManagerHandler extends Handler {
+ public DisplayManagerHandler(Looper looper) {
+ super(looper, null, true /*async*/);
}
- pw.println("Default display: "
- + DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY));
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
+ registerDefaultDisplayAdapter();
+ break;
+
+ case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
+ registerAdditionalDisplayAdapters();
+ break;
+
+ case MSG_DELIVER_DISPLAY_EVENT:
+ deliverDisplayEvent(msg.arg1, msg.arg2);
+ break;
+ }
+ }
+ }
+
+ private final class DisplayAdapterListener implements DisplayAdapter.Listener {
+ @Override
+ public void onDisplayDeviceEvent(DisplayDevice device, int event) {
+ switch (event) {
+ case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
+ handleDisplayDeviceAdded(device);
+ break;
+
+ case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
+ handleDisplayDeviceChanged(device);
+ break;
+
+ case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
+ handleDisplayDeviceRemoved(device);
+ break;
+ }
+ }
+ }
+
+ private final class CallbackRecord implements DeathRecipient {
+ private final int mPid;
+ private final IDisplayManagerCallback mCallback;
+
+ public CallbackRecord(int pid, IDisplayManagerCallback callback) {
+ mPid = pid;
+ mCallback = callback;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DEBUG) {
+ Slog.d(TAG, "Display listener for pid " + mPid + " died.");
+ }
+ onCallbackDied(mPid);
+ }
+
+ public void notifyDisplayEventAsync(int displayId, int event) {
+ try {
+ mCallback.onDisplayEvent(displayId, event);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process "
+ + mPid + " that displays changed, assuming it died.", ex);
+ binderDied();
+ }
+ }
+ }
+
+ /**
+ * Each logical display is primarily associated with one display device.
+ * The primary display device is nominally responsible for the basic properties
+ * of the logical display such as its size, refresh rate, and dpi.
+ *
+ * A logical display may be mirrored onto other display devices besides its
+ * primary display device, but it always remains bound to its primary.
+ * Note that the contents of a logical display may not always be visible, even
+ * on its primary display device, such as in the case where the logical display's
+ * primary display device is currently mirroring content from a different logical display.
+ */
+ private final static class LogicalDisplay {
+ public final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
+ public DisplayInfo mOverrideDisplayInfo; // set by the window manager
+
+ public final DisplayDevice mPrimaryDisplayDevice;
+ public final DisplayDeviceInfo mPrimaryDisplayDeviceInfo = new DisplayDeviceInfo();
+
+ public LogicalDisplay(DisplayDevice primaryDisplayDevice) {
+ mPrimaryDisplayDevice = primaryDisplayDevice;
+ }
+
+ public void updateFromPrimaryDisplayDevice() {
+ // Bootstrap the logical display using its associated primary physical display.
+ mPrimaryDisplayDevice.getInfo(mPrimaryDisplayDeviceInfo);
+
+ mBaseDisplayInfo.appWidth = mPrimaryDisplayDeviceInfo.width;
+ mBaseDisplayInfo.appHeight = mPrimaryDisplayDeviceInfo.height;
+ mBaseDisplayInfo.logicalWidth = mPrimaryDisplayDeviceInfo.width;
+ mBaseDisplayInfo.logicalHeight = mPrimaryDisplayDeviceInfo.height;
+ mBaseDisplayInfo.rotation = Surface.ROTATION_0;
+ mBaseDisplayInfo.refreshRate = mPrimaryDisplayDeviceInfo.refreshRate;
+ mBaseDisplayInfo.logicalDensityDpi = mPrimaryDisplayDeviceInfo.densityDpi;
+ mBaseDisplayInfo.physicalXDpi = mPrimaryDisplayDeviceInfo.xDpi;
+ mBaseDisplayInfo.physicalYDpi = mPrimaryDisplayDeviceInfo.yDpi;
+ mBaseDisplayInfo.smallestNominalAppWidth = mPrimaryDisplayDeviceInfo.width;
+ mBaseDisplayInfo.smallestNominalAppHeight = mPrimaryDisplayDeviceInfo.height;
+ mBaseDisplayInfo.largestNominalAppWidth = mPrimaryDisplayDeviceInfo.width;
+ mBaseDisplayInfo.largestNominalAppHeight = mPrimaryDisplayDeviceInfo.height;
+ }
}
}