Home | History | Annotate | Download | only in display
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.display;
     18 
     19 import android.graphics.Rect;
     20 import android.hardware.display.DisplayManagerInternal;
     21 import android.view.Display;
     22 import android.view.DisplayInfo;
     23 import android.view.Surface;
     24 
     25 import java.io.PrintWriter;
     26 import java.util.Arrays;
     27 import java.util.List;
     28 
     29 import libcore.util.Objects;
     30 
     31 /**
     32  * Describes how a logical display is configured.
     33  * <p>
     34  * At this time, we only support logical displays that are coupled to a particular
     35  * primary display device from which the logical display derives its basic properties
     36  * such as its size, density and refresh rate.
     37  * </p><p>
     38  * A logical display may be mirrored onto multiple display devices in addition to its
     39  * primary display device.  Note that the contents of a logical display may not
     40  * always be visible, even on its primary display device, such as in the case where
     41  * the primary display device is currently mirroring content from a different
     42  * logical display.
     43  * </p><p>
     44  * This object is designed to encapsulate as much of the policy of logical
     45  * displays as possible.  The idea is to make it easy to implement new kinds of
     46  * logical displays mostly by making local changes to this class.
     47  * </p><p>
     48  * Note: The display manager architecture does not actually require logical displays
     49  * to be associated with any individual display device.  Logical displays and
     50  * display devices are orthogonal concepts.  Some mapping will exist between
     51  * logical displays and display devices but it can be many-to-many and
     52  * and some might have no relation at all.
     53  * </p><p>
     54  * Logical displays are guarded by the {@link DisplayManagerService.SyncRoot} lock.
     55  * </p>
     56  */
     57 final class LogicalDisplay {
     58     private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
     59 
     60     // The layer stack we use when the display has been blanked to prevent any
     61     // of its content from appearing.
     62     private static final int BLANK_LAYER_STACK = -1;
     63 
     64     private final int mDisplayId;
     65     private final int mLayerStack;
     66     /**
     67      * Override information set by the window manager. Will be reported instead of {@link #mInfo}
     68      * if not null.
     69      * @see #setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo)
     70      * @see #getDisplayInfoLocked()
     71      */
     72     private DisplayInfo mOverrideDisplayInfo;
     73     /**
     74      * Current display info. Initialized with {@link #mBaseDisplayInfo}. Set to {@code null} if
     75      * needs to be updated.
     76      * @see #getDisplayInfoLocked()
     77      */
     78     private DisplayInfo mInfo;
     79 
     80     // The display device that this logical display is based on and which
     81     // determines the base metrics that it uses.
     82     private DisplayDevice mPrimaryDisplayDevice;
     83     private DisplayDeviceInfo mPrimaryDisplayDeviceInfo;
     84 
     85     // True if the logical display has unique content.
     86     private boolean mHasContent;
     87 
     88     private int mRequestedModeId;
     89     private int mRequestedColorMode;
     90 
     91     // The display offsets to apply to the display projection.
     92     private int mDisplayOffsetX;
     93     private int mDisplayOffsetY;
     94 
     95     // Temporary rectangle used when needed.
     96     private final Rect mTempLayerStackRect = new Rect();
     97     private final Rect mTempDisplayRect = new Rect();
     98 
     99     public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
    100         mDisplayId = displayId;
    101         mLayerStack = layerStack;
    102         mPrimaryDisplayDevice = primaryDisplayDevice;
    103     }
    104 
    105     /**
    106      * Gets the logical display id of this logical display.
    107      *
    108      * @return The logical display id.
    109      */
    110     public int getDisplayIdLocked() {
    111         return mDisplayId;
    112     }
    113 
    114     /**
    115      * Gets the primary display device associated with this logical display.
    116      *
    117      * @return The primary display device.
    118      */
    119     public DisplayDevice getPrimaryDisplayDeviceLocked() {
    120         return mPrimaryDisplayDevice;
    121     }
    122 
    123     /**
    124      * Gets information about the logical display.
    125      *
    126      * @return The device info, which should be treated as immutable by the caller.
    127      * The logical display should allocate a new display info object whenever
    128      * the data changes.
    129      */
    130     public DisplayInfo getDisplayInfoLocked() {
    131         if (mInfo == null) {
    132             mInfo = new DisplayInfo();
    133             mInfo.copyFrom(mBaseDisplayInfo);
    134             if (mOverrideDisplayInfo != null) {
    135                 mInfo.appWidth = mOverrideDisplayInfo.appWidth;
    136                 mInfo.appHeight = mOverrideDisplayInfo.appHeight;
    137                 mInfo.smallestNominalAppWidth = mOverrideDisplayInfo.smallestNominalAppWidth;
    138                 mInfo.smallestNominalAppHeight = mOverrideDisplayInfo.smallestNominalAppHeight;
    139                 mInfo.largestNominalAppWidth = mOverrideDisplayInfo.largestNominalAppWidth;
    140                 mInfo.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
    141                 mInfo.logicalWidth = mOverrideDisplayInfo.logicalWidth;
    142                 mInfo.logicalHeight = mOverrideDisplayInfo.logicalHeight;
    143                 mInfo.overscanLeft = mOverrideDisplayInfo.overscanLeft;
    144                 mInfo.overscanTop = mOverrideDisplayInfo.overscanTop;
    145                 mInfo.overscanRight = mOverrideDisplayInfo.overscanRight;
    146                 mInfo.overscanBottom = mOverrideDisplayInfo.overscanBottom;
    147                 mInfo.rotation = mOverrideDisplayInfo.rotation;
    148                 mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
    149                 mInfo.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
    150                 mInfo.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
    151             }
    152         }
    153         return mInfo;
    154     }
    155 
    156     /**
    157      * @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo)
    158      */
    159     void getNonOverrideDisplayInfoLocked(DisplayInfo outInfo) {
    160         outInfo.copyFrom(mBaseDisplayInfo);
    161     }
    162 
    163     /**
    164      * Sets overridden logical display information from the window manager.
    165      * This method can be used to adjust application insets, rotation, and other
    166      * properties that the window manager takes care of.
    167      *
    168      * @param info The logical display information, may be null.
    169      */
    170     public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
    171         if (info != null) {
    172             if (mOverrideDisplayInfo == null) {
    173                 mOverrideDisplayInfo = new DisplayInfo(info);
    174                 mInfo = null;
    175                 return true;
    176             }
    177             if (!mOverrideDisplayInfo.equals(info)) {
    178                 mOverrideDisplayInfo.copyFrom(info);
    179                 mInfo = null;
    180                 return true;
    181             }
    182         } else if (mOverrideDisplayInfo != null) {
    183             mOverrideDisplayInfo = null;
    184             mInfo = null;
    185             return true;
    186         }
    187         return false;
    188     }
    189 
    190     /**
    191      * Returns true if the logical display is in a valid state.
    192      * This method should be checked after calling {@link #updateLocked} to handle the
    193      * case where a logical display should be removed because all of its associated
    194      * display devices are gone or if it is otherwise no longer needed.
    195      *
    196      * @return True if the logical display is still valid.
    197      */
    198     public boolean isValidLocked() {
    199         return mPrimaryDisplayDevice != null;
    200     }
    201 
    202     /**
    203      * Updates the state of the logical display based on the available display devices.
    204      * The logical display might become invalid if it is attached to a display device
    205      * that no longer exists.
    206      *
    207      * @param devices The list of all connected display devices.
    208      */
    209     public void updateLocked(List<DisplayDevice> devices) {
    210         // Nothing to update if already invalid.
    211         if (mPrimaryDisplayDevice == null) {
    212             return;
    213         }
    214 
    215         // Check whether logical display has become invalid.
    216         if (!devices.contains(mPrimaryDisplayDevice)) {
    217             mPrimaryDisplayDevice = null;
    218             return;
    219         }
    220 
    221         // Bootstrap the logical display using its associated primary physical display.
    222         // We might use more elaborate configurations later.  It's possible that the
    223         // configuration of several physical displays might be used to determine the
    224         // logical display that they are sharing.  (eg. Adjust size for pixel-perfect
    225         // mirroring over HDMI.)
    226         DisplayDeviceInfo deviceInfo = mPrimaryDisplayDevice.getDisplayDeviceInfoLocked();
    227         if (!Objects.equal(mPrimaryDisplayDeviceInfo, deviceInfo)) {
    228             mBaseDisplayInfo.layerStack = mLayerStack;
    229             mBaseDisplayInfo.flags = 0;
    230             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
    231                 mBaseDisplayInfo.flags |= Display.FLAG_SUPPORTS_PROTECTED_BUFFERS;
    232             }
    233             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SECURE) != 0) {
    234                 mBaseDisplayInfo.flags |= Display.FLAG_SECURE;
    235             }
    236             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0) {
    237                 mBaseDisplayInfo.flags |= Display.FLAG_PRIVATE;
    238                 // For private displays by default content is destroyed on removal.
    239                 mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT;
    240             }
    241             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRESENTATION) != 0) {
    242                 mBaseDisplayInfo.flags |= Display.FLAG_PRESENTATION;
    243             }
    244             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ROUND) != 0) {
    245                 mBaseDisplayInfo.flags |= Display.FLAG_ROUND;
    246             }
    247             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
    248                 mBaseDisplayInfo.flags |= Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
    249             }
    250             mBaseDisplayInfo.type = deviceInfo.type;
    251             mBaseDisplayInfo.address = deviceInfo.address;
    252             mBaseDisplayInfo.name = deviceInfo.name;
    253             mBaseDisplayInfo.uniqueId = deviceInfo.uniqueId;
    254             mBaseDisplayInfo.appWidth = deviceInfo.width;
    255             mBaseDisplayInfo.appHeight = deviceInfo.height;
    256             mBaseDisplayInfo.logicalWidth = deviceInfo.width;
    257             mBaseDisplayInfo.logicalHeight = deviceInfo.height;
    258             mBaseDisplayInfo.rotation = Surface.ROTATION_0;
    259             mBaseDisplayInfo.modeId = deviceInfo.modeId;
    260             mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
    261             mBaseDisplayInfo.supportedModes = Arrays.copyOf(
    262                     deviceInfo.supportedModes, deviceInfo.supportedModes.length);
    263             mBaseDisplayInfo.colorMode = deviceInfo.colorMode;
    264             mBaseDisplayInfo.supportedColorModes = Arrays.copyOf(
    265                     deviceInfo.supportedColorModes,
    266                     deviceInfo.supportedColorModes.length);
    267             mBaseDisplayInfo.hdrCapabilities = deviceInfo.hdrCapabilities;
    268             mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
    269             mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
    270             mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
    271             mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos;
    272             mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos;
    273             mBaseDisplayInfo.state = deviceInfo.state;
    274             mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
    275             mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
    276             mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
    277             mBaseDisplayInfo.largestNominalAppHeight = deviceInfo.height;
    278             mBaseDisplayInfo.ownerUid = deviceInfo.ownerUid;
    279             mBaseDisplayInfo.ownerPackageName = deviceInfo.ownerPackageName;
    280 
    281             mPrimaryDisplayDeviceInfo = deviceInfo;
    282             mInfo = null;
    283         }
    284     }
    285 
    286     /**
    287      * Applies the layer stack and transformation to the given display device
    288      * so that it shows the contents of this logical display.
    289      *
    290      * We know that the given display device is only ever showing the contents of
    291      * a single logical display, so this method is expected to blow away all of its
    292      * transformation properties to make it happen regardless of what the
    293      * display device was previously showing.
    294      *
    295      * The caller must have an open Surface transaction.
    296      *
    297      * The display device may not be the primary display device, in the case
    298      * where the display is being mirrored.
    299      *
    300      * @param device The display device to modify.
    301      * @param isBlanked True if the device is being blanked.
    302      */
    303     public void configureDisplayInTransactionLocked(DisplayDevice device,
    304             boolean isBlanked) {
    305         // Set the layer stack.
    306         device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
    307 
    308         // Set the color mode and mode.
    309         if (device == mPrimaryDisplayDevice) {
    310             device.requestDisplayModesInTransactionLocked(
    311                     mRequestedColorMode, mRequestedModeId);
    312         } else {
    313             device.requestDisplayModesInTransactionLocked(0, 0);  // Revert to default.
    314         }
    315 
    316         // Only grab the display info now as it may have been changed based on the requests above.
    317         final DisplayInfo displayInfo = getDisplayInfoLocked();
    318         final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();
    319 
    320         // Set the viewport.
    321         // This is the area of the logical display that we intend to show on the
    322         // display device.  For now, it is always the full size of the logical display.
    323         mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
    324 
    325         // Set the orientation.
    326         // The orientation specifies how the physical coordinate system of the display
    327         // is rotated when the contents of the logical display are rendered.
    328         int orientation = Surface.ROTATION_0;
    329         if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
    330             orientation = displayInfo.rotation;
    331         }
    332 
    333         // Apply the physical rotation of the display device itself.
    334         orientation = (orientation + displayDeviceInfo.rotation) % 4;
    335 
    336         // Set the frame.
    337         // The frame specifies the rotated physical coordinates into which the viewport
    338         // is mapped.  We need to take care to preserve the aspect ratio of the viewport.
    339         // Currently we maximize the area to fill the display, but we could try to be
    340         // more clever and match resolutions.
    341         boolean rotated = (orientation == Surface.ROTATION_90
    342                 || orientation == Surface.ROTATION_270);
    343         int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
    344         int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
    345 
    346         // Determine whether the width or height is more constrained to be scaled.
    347         //    physWidth / displayInfo.logicalWidth    => letter box
    348         // or physHeight / displayInfo.logicalHeight  => pillar box
    349         //
    350         // We avoid a division (and possible floating point imprecision) here by
    351         // multiplying the fractions by the product of their denominators before
    352         // comparing them.
    353         int displayRectWidth, displayRectHeight;
    354         if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0) {
    355             displayRectWidth = displayInfo.logicalWidth;
    356             displayRectHeight = displayInfo.logicalHeight;
    357         } else if (physWidth * displayInfo.logicalHeight
    358                 < physHeight * displayInfo.logicalWidth) {
    359             // Letter box.
    360             displayRectWidth = physWidth;
    361             displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
    362         } else {
    363             // Pillar box.
    364             displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
    365             displayRectHeight = physHeight;
    366         }
    367         int displayRectTop = (physHeight - displayRectHeight) / 2;
    368         int displayRectLeft = (physWidth - displayRectWidth) / 2;
    369         mTempDisplayRect.set(displayRectLeft, displayRectTop,
    370                 displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
    371 
    372         mTempDisplayRect.left += mDisplayOffsetX;
    373         mTempDisplayRect.right += mDisplayOffsetX;
    374         mTempDisplayRect.top += mDisplayOffsetY;
    375         mTempDisplayRect.bottom += mDisplayOffsetY;
    376         device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
    377     }
    378 
    379     /**
    380      * Returns true if the logical display has unique content.
    381      * <p>
    382      * If the display has unique content then we will try to ensure that it is
    383      * visible on at least its primary display device.  Otherwise we will ignore the
    384      * logical display and perhaps show mirrored content on the primary display device.
    385      * </p>
    386      *
    387      * @return True if the display has unique content.
    388      */
    389     public boolean hasContentLocked() {
    390         return mHasContent;
    391     }
    392 
    393     /**
    394      * Sets whether the logical display has unique content.
    395      *
    396      * @param hasContent True if the display has unique content.
    397      */
    398     public void setHasContentLocked(boolean hasContent) {
    399         mHasContent = hasContent;
    400     }
    401 
    402     /**
    403      * Requests the given mode.
    404      */
    405     public void setRequestedModeIdLocked(int modeId) {
    406         mRequestedModeId = modeId;
    407     }
    408 
    409     /**
    410      * Returns the pending requested mode.
    411      */
    412     public int getRequestedModeIdLocked() {
    413         return mRequestedModeId;
    414     }
    415 
    416     /**
    417      * Requests the given color mode.
    418      */
    419     public void setRequestedColorModeLocked(int colorMode) {
    420         mRequestedColorMode = colorMode;
    421     }
    422 
    423     /** Returns the pending requested color mode. */
    424     public int getRequestedColorModeLocked() {
    425         return mRequestedColorMode;
    426     }
    427 
    428     /**
    429      * Gets the burn-in offset in X.
    430      */
    431     public int getDisplayOffsetXLocked() {
    432         return mDisplayOffsetX;
    433     }
    434 
    435     /**
    436      * Gets the burn-in offset in Y.
    437      */
    438     public int getDisplayOffsetYLocked() {
    439         return mDisplayOffsetY;
    440     }
    441 
    442     /**
    443      * Sets the burn-in offsets.
    444      */
    445     public void setDisplayOffsetsLocked(int x, int y) {
    446         mDisplayOffsetX = x;
    447         mDisplayOffsetY = y;
    448     }
    449 
    450     public void dumpLocked(PrintWriter pw) {
    451         pw.println("mDisplayId=" + mDisplayId);
    452         pw.println("mLayerStack=" + mLayerStack);
    453         pw.println("mHasContent=" + mHasContent);
    454         pw.println("mRequestedMode=" + mRequestedModeId);
    455         pw.println("mRequestedColorMode=" + mRequestedColorMode);
    456         pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")");
    457         pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
    458                 mPrimaryDisplayDevice.getNameLocked() : "null"));
    459         pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
    460         pw.println("mOverrideDisplayInfo=" + mOverrideDisplayInfo);
    461     }
    462 }
    463