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