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.view.Display;
     21 import android.view.DisplayInfo;
     22 import android.view.Surface;
     23 
     24 import java.io.PrintWriter;
     25 import java.util.List;
     26 
     27 import libcore.util.Objects;
     28 
     29 /**
     30  * Describes how a logical display is configured.
     31  * <p>
     32  * At this time, we only support logical displays that are coupled to a particular
     33  * primary display device from which the logical display derives its basic properties
     34  * such as its size, density and refresh rate.
     35  * </p><p>
     36  * A logical display may be mirrored onto multiple display devices in addition to its
     37  * primary display device.  Note that the contents of a logical display may not
     38  * always be visible, even on its primary display device, such as in the case where
     39  * the primary display device is currently mirroring content from a different
     40  * logical display.
     41  * </p><p>
     42  * This object is designed to encapsulate as much of the policy of logical
     43  * displays as possible.  The idea is to make it easy to implement new kinds of
     44  * logical displays mostly by making local changes to this class.
     45  * </p><p>
     46  * Note: The display manager architecture does not actually require logical displays
     47  * to be associated with any individual display device.  Logical displays and
     48  * display devices are orthogonal concepts.  Some mapping will exist between
     49  * logical displays and display devices but it can be many-to-many and
     50  * and some might have no relation at all.
     51  * </p><p>
     52  * Logical displays are guarded by the {@link DisplayManagerService.SyncRoot} lock.
     53  * </p>
     54  */
     55 final class LogicalDisplay {
     56     private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
     57 
     58     // The layer stack we use when the display has been blanked to prevent any
     59     // of its content from appearing.
     60     private static final int BLANK_LAYER_STACK = -1;
     61 
     62     private final int mDisplayId;
     63     private final int mLayerStack;
     64     private DisplayInfo mOverrideDisplayInfo; // set by the window manager
     65     private DisplayInfo mInfo;
     66 
     67     // The display device that this logical display is based on and which
     68     // determines the base metrics that it uses.
     69     private DisplayDevice mPrimaryDisplayDevice;
     70     private DisplayDeviceInfo mPrimaryDisplayDeviceInfo;
     71 
     72     // True if the logical display has unique content.
     73     private boolean mHasContent;
     74 
     75     // Temporary rectangle used when needed.
     76     private final Rect mTempLayerStackRect = new Rect();
     77     private final Rect mTempDisplayRect = new Rect();
     78 
     79     public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
     80         mDisplayId = displayId;
     81         mLayerStack = layerStack;
     82         mPrimaryDisplayDevice = primaryDisplayDevice;
     83     }
     84 
     85     /**
     86      * Gets the logical display id of this logical display.
     87      *
     88      * @return The logical display id.
     89      */
     90     public int getDisplayIdLocked() {
     91         return mDisplayId;
     92     }
     93 
     94     /**
     95      * Gets the primary display device associated with this logical display.
     96      *
     97      * @return The primary display device.
     98      */
     99     public DisplayDevice getPrimaryDisplayDeviceLocked() {
    100         return mPrimaryDisplayDevice;
    101     }
    102 
    103     /**
    104      * Gets information about the logical display.
    105      *
    106      * @return The device info, which should be treated as immutable by the caller.
    107      * The logical display should allocate a new display info object whenever
    108      * the data changes.
    109      */
    110     public DisplayInfo getDisplayInfoLocked() {
    111         if (mInfo == null) {
    112             mInfo = new DisplayInfo();
    113             if (mOverrideDisplayInfo != null) {
    114                 mInfo.copyFrom(mOverrideDisplayInfo);
    115                 mInfo.layerStack = mBaseDisplayInfo.layerStack;
    116                 mInfo.name = mBaseDisplayInfo.name;
    117             } else {
    118                 mInfo.copyFrom(mBaseDisplayInfo);
    119             }
    120         }
    121         return mInfo;
    122     }
    123 
    124     /**
    125      * Sets overridden logical display information from the window manager.
    126      * This method can be used to adjust application insets, rotation, and other
    127      * properties that the window manager takes care of.
    128      *
    129      * @param info The logical display information, may be null.
    130      */
    131     public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
    132         if (info != null) {
    133             if (mOverrideDisplayInfo == null) {
    134                 mOverrideDisplayInfo = new DisplayInfo(info);
    135                 mInfo = null;
    136                 return true;
    137             }
    138             if (!mOverrideDisplayInfo.equals(info)) {
    139                 mOverrideDisplayInfo.copyFrom(info);
    140                 mInfo = null;
    141                 return true;
    142             }
    143         } else if (mOverrideDisplayInfo != null) {
    144             mOverrideDisplayInfo = null;
    145             mInfo = null;
    146             return true;
    147         }
    148         return false;
    149     }
    150 
    151     /**
    152      * Returns true if the logical display is in a valid state.
    153      * This method should be checked after calling {@link #updateLocked} to handle the
    154      * case where a logical display should be removed because all of its associated
    155      * display devices are gone or if it is otherwise no longer needed.
    156      *
    157      * @return True if the logical display is still valid.
    158      */
    159     public boolean isValidLocked() {
    160         return mPrimaryDisplayDevice != null;
    161     }
    162 
    163     /**
    164      * Updates the state of the logical display based on the available display devices.
    165      * The logical display might become invalid if it is attached to a display device
    166      * that no longer exists.
    167      *
    168      * @param devices The list of all connected display devices.
    169      */
    170     public void updateLocked(List<DisplayDevice> devices) {
    171         // Nothing to update if already invalid.
    172         if (mPrimaryDisplayDevice == null) {
    173             return;
    174         }
    175 
    176         // Check whether logical display has become invalid.
    177         if (!devices.contains(mPrimaryDisplayDevice)) {
    178             mPrimaryDisplayDevice = null;
    179             return;
    180         }
    181 
    182         // Bootstrap the logical display using its associated primary physical display.
    183         // We might use more elaborate configurations later.  It's possible that the
    184         // configuration of several physical displays might be used to determine the
    185         // logical display that they are sharing.  (eg. Adjust size for pixel-perfect
    186         // mirroring over HDMI.)
    187         DisplayDeviceInfo deviceInfo = mPrimaryDisplayDevice.getDisplayDeviceInfoLocked();
    188         if (!Objects.equal(mPrimaryDisplayDeviceInfo, deviceInfo)) {
    189             mBaseDisplayInfo.layerStack = mLayerStack;
    190             mBaseDisplayInfo.flags = 0;
    191             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
    192                 mBaseDisplayInfo.flags |= Display.FLAG_SUPPORTS_PROTECTED_BUFFERS;
    193             }
    194             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SECURE) != 0) {
    195                 mBaseDisplayInfo.flags |= Display.FLAG_SECURE;
    196             }
    197             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0) {
    198                 mBaseDisplayInfo.flags |= Display.FLAG_PRIVATE;
    199             }
    200             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRESENTATION) != 0) {
    201                 mBaseDisplayInfo.flags |= Display.FLAG_PRESENTATION;
    202             }
    203             mBaseDisplayInfo.type = deviceInfo.type;
    204             mBaseDisplayInfo.address = deviceInfo.address;
    205             mBaseDisplayInfo.name = deviceInfo.name;
    206             mBaseDisplayInfo.appWidth = deviceInfo.width;
    207             mBaseDisplayInfo.appHeight = deviceInfo.height;
    208             mBaseDisplayInfo.logicalWidth = deviceInfo.width;
    209             mBaseDisplayInfo.logicalHeight = deviceInfo.height;
    210             mBaseDisplayInfo.rotation = Surface.ROTATION_0;
    211             mBaseDisplayInfo.refreshRate = deviceInfo.refreshRate;
    212             mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
    213             mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
    214             mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
    215             mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
    216             mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
    217             mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
    218             mBaseDisplayInfo.largestNominalAppHeight = deviceInfo.height;
    219             mBaseDisplayInfo.ownerUid = deviceInfo.ownerUid;
    220             mBaseDisplayInfo.ownerPackageName = deviceInfo.ownerPackageName;
    221 
    222             mPrimaryDisplayDeviceInfo = deviceInfo;
    223             mInfo = null;
    224         }
    225     }
    226 
    227     /**
    228      * Applies the layer stack and transformation to the given display device
    229      * so that it shows the contents of this logical display.
    230      *
    231      * We know that the given display device is only ever showing the contents of
    232      * a single logical display, so this method is expected to blow away all of its
    233      * transformation properties to make it happen regardless of what the
    234      * display device was previously showing.
    235      *
    236      * The caller must have an open Surface transaction.
    237      *
    238      * The display device may not be the primary display device, in the case
    239      * where the display is being mirrored.
    240      *
    241      * @param device The display device to modify.
    242      * @param isBlanked True if the device is being blanked.
    243      */
    244     public void configureDisplayInTransactionLocked(DisplayDevice device,
    245             boolean isBlanked) {
    246         final DisplayInfo displayInfo = getDisplayInfoLocked();
    247         final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();
    248 
    249         // Set the layer stack.
    250         device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
    251 
    252         // Set the viewport.
    253         // This is the area of the logical display that we intend to show on the
    254         // display device.  For now, it is always the full size of the logical display.
    255         mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
    256 
    257         // Set the orientation.
    258         // The orientation specifies how the physical coordinate system of the display
    259         // is rotated when the contents of the logical display are rendered.
    260         int orientation = Surface.ROTATION_0;
    261         if (device == mPrimaryDisplayDevice
    262                 && (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
    263             orientation = displayInfo.rotation;
    264         }
    265 
    266         // Apply the physical rotation of the display device itself.
    267         orientation = (orientation + displayDeviceInfo.rotation) % 4;
    268 
    269         // Set the frame.
    270         // The frame specifies the rotated physical coordinates into which the viewport
    271         // is mapped.  We need to take care to preserve the aspect ratio of the viewport.
    272         // Currently we maximize the area to fill the display, but we could try to be
    273         // more clever and match resolutions.
    274         boolean rotated = (orientation == Surface.ROTATION_90
    275                 || orientation == Surface.ROTATION_270);
    276         int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
    277         int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
    278 
    279         // Determine whether the width or height is more constrained to be scaled.
    280         //    physWidth / displayInfo.logicalWidth    => letter box
    281         // or physHeight / displayInfo.logicalHeight  => pillar box
    282         //
    283         // We avoid a division (and possible floating point imprecision) here by
    284         // multiplying the fractions by the product of their denominators before
    285         // comparing them.
    286         int displayRectWidth, displayRectHeight;
    287         if (physWidth * displayInfo.logicalHeight
    288                 < physHeight * displayInfo.logicalWidth) {
    289             // Letter box.
    290             displayRectWidth = physWidth;
    291             displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
    292         } else {
    293             // Pillar box.
    294             displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
    295             displayRectHeight = physHeight;
    296         }
    297         int displayRectTop = (physHeight - displayRectHeight) / 2;
    298         int displayRectLeft = (physWidth - displayRectWidth) / 2;
    299         mTempDisplayRect.set(displayRectLeft, displayRectTop,
    300                 displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
    301 
    302         device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
    303     }
    304 
    305     /**
    306      * Returns true if the logical display has unique content.
    307      * <p>
    308      * If the display has unique content then we will try to ensure that it is
    309      * visible on at least its primary display device.  Otherwise we will ignore the
    310      * logical display and perhaps show mirrored content on the primary display device.
    311      * </p>
    312      *
    313      * @return True if the display has unique content.
    314      */
    315     public boolean hasContentLocked() {
    316         return mHasContent;
    317     }
    318 
    319     /**
    320      * Sets whether the logical display has unique content.
    321      *
    322      * @param hasContent True if the display has unique content.
    323      */
    324     public void setHasContentLocked(boolean hasContent) {
    325         mHasContent = hasContent;
    326     }
    327 
    328     public void dumpLocked(PrintWriter pw) {
    329         pw.println("mDisplayId=" + mDisplayId);
    330         pw.println("mLayerStack=" + mLayerStack);
    331         pw.println("mHasContent=" + mHasContent);
    332         pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
    333                 mPrimaryDisplayDevice.getNameLocked() : "null"));
    334         pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
    335         pw.println("mOverrideDisplayInfo=" + mOverrideDisplayInfo);
    336     }
    337 }