Home | History | Annotate | Download | only in view
      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 android.view;
     18 
     19 import static android.view.DisplayInfoProto.APP_HEIGHT;
     20 import static android.view.DisplayInfoProto.APP_WIDTH;
     21 import static android.view.DisplayInfoProto.LOGICAL_HEIGHT;
     22 import static android.view.DisplayInfoProto.LOGICAL_WIDTH;
     23 import static android.view.DisplayInfoProto.NAME;
     24 
     25 import android.annotation.Nullable;
     26 import android.annotation.UnsupportedAppUsage;
     27 import android.content.res.CompatibilityInfo;
     28 import android.content.res.Configuration;
     29 import android.graphics.Rect;
     30 import android.os.Build;
     31 import android.os.Parcel;
     32 import android.os.Parcelable;
     33 import android.util.ArraySet;
     34 import android.util.DisplayMetrics;
     35 import android.util.proto.ProtoOutputStream;
     36 
     37 import java.util.Arrays;
     38 import java.util.Objects;
     39 
     40 /**
     41  * Describes the characteristics of a particular logical display.
     42  * @hide
     43  */
     44 public final class DisplayInfo implements Parcelable {
     45     /**
     46      * The surface flinger layer stack associated with this logical display.
     47      */
     48     public int layerStack;
     49 
     50     /**
     51      * Display flags.
     52      */
     53     public int flags;
     54 
     55     /**
     56      * Display type.
     57      */
     58     public int type;
     59 
     60     /**
     61      * Logical display identifier.
     62      */
     63     public int displayId;
     64 
     65     /**
     66      * Display address, or null if none.
     67      * Interpretation varies by display type.
     68      */
     69     public DisplayAddress address;
     70 
     71     /**
     72      * The human-readable name of the display.
     73      */
     74     public String name;
     75 
     76     /**
     77      * Unique identifier for the display. Shouldn't be displayed to the user.
     78      */
     79     public String uniqueId;
     80 
     81     /**
     82      * The width of the portion of the display that is available to applications, in pixels.
     83      * Represents the size of the display minus any system decorations.
     84      */
     85     public int appWidth;
     86 
     87     /**
     88      * The height of the portion of the display that is available to applications, in pixels.
     89      * Represents the size of the display minus any system decorations.
     90      */
     91     public int appHeight;
     92 
     93     /**
     94      * The smallest value of {@link #appWidth} that an application is likely to encounter,
     95      * in pixels, excepting cases where the width may be even smaller due to the presence
     96      * of a soft keyboard, for example.
     97      */
     98     public int smallestNominalAppWidth;
     99 
    100     /**
    101      * The smallest value of {@link #appHeight} that an application is likely to encounter,
    102      * in pixels, excepting cases where the height may be even smaller due to the presence
    103      * of a soft keyboard, for example.
    104      */
    105     public int smallestNominalAppHeight;
    106 
    107     /**
    108      * The largest value of {@link #appWidth} that an application is likely to encounter,
    109      * in pixels, excepting cases where the width may be even larger due to system decorations
    110      * such as the status bar being hidden, for example.
    111      */
    112     public int largestNominalAppWidth;
    113 
    114     /**
    115      * The largest value of {@link #appHeight} that an application is likely to encounter,
    116      * in pixels, excepting cases where the height may be even larger due to system decorations
    117      * such as the status bar being hidden, for example.
    118      */
    119     public int largestNominalAppHeight;
    120 
    121     /**
    122      * The logical width of the display, in pixels.
    123      * Represents the usable size of the display which may be smaller than the
    124      * physical size when the system is emulating a smaller display.
    125      */
    126     @UnsupportedAppUsage
    127     public int logicalWidth;
    128 
    129     /**
    130      * The logical height of the display, in pixels.
    131      * Represents the usable size of the display which may be smaller than the
    132      * physical size when the system is emulating a smaller display.
    133      */
    134     @UnsupportedAppUsage
    135     public int logicalHeight;
    136 
    137     /**
    138      * @hide
    139      * Number of overscan pixels on the left side of the display.
    140      */
    141     public int overscanLeft;
    142 
    143     /**
    144      * @hide
    145      * Number of overscan pixels on the top side of the display.
    146      */
    147     public int overscanTop;
    148 
    149     /**
    150      * @hide
    151      * Number of overscan pixels on the right side of the display.
    152      */
    153     public int overscanRight;
    154 
    155     /**
    156      * @hide
    157      * Number of overscan pixels on the bottom side of the display.
    158      */
    159     public int overscanBottom;
    160 
    161     /**
    162      * The {@link DisplayCutout} if present, otherwise {@code null}.
    163      *
    164      * @hide
    165      */
    166     // Remark on @UnsupportedAppUsage: Display.getCutout should be used instead
    167     @Nullable
    168     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    169     public DisplayCutout displayCutout;
    170 
    171     /**
    172      * The rotation of the display relative to its natural orientation.
    173      * May be one of {@link android.view.Surface#ROTATION_0},
    174      * {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
    175      * {@link android.view.Surface#ROTATION_270}.
    176      * <p>
    177      * The value of this field is indeterminate if the logical display is presented on
    178      * more than one physical display.
    179      * </p>
    180      */
    181     @Surface.Rotation
    182     @UnsupportedAppUsage
    183     public int rotation;
    184 
    185     /**
    186      * The active display mode.
    187      */
    188     public int modeId;
    189 
    190     /**
    191      * The default display mode.
    192      */
    193     public int defaultModeId;
    194 
    195     /**
    196      * The supported modes of this display.
    197      */
    198     public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
    199 
    200     /** The active color mode. */
    201     public int colorMode;
    202 
    203     /** The list of supported color modes */
    204     public int[] supportedColorModes = { Display.COLOR_MODE_DEFAULT };
    205 
    206     /** The display's HDR capabilities */
    207     public Display.HdrCapabilities hdrCapabilities;
    208 
    209     /**
    210      * The logical display density which is the basis for density-independent
    211      * pixels.
    212      */
    213     public int logicalDensityDpi;
    214 
    215     /**
    216      * The exact physical pixels per inch of the screen in the X dimension.
    217      * <p>
    218      * The value of this field is indeterminate if the logical display is presented on
    219      * more than one physical display.
    220      * </p>
    221      */
    222     public float physicalXDpi;
    223 
    224     /**
    225      * The exact physical pixels per inch of the screen in the Y dimension.
    226      * <p>
    227      * The value of this field is indeterminate if the logical display is presented on
    228      * more than one physical display.
    229      * </p>
    230      */
    231     public float physicalYDpi;
    232 
    233     /**
    234      * This is a positive value indicating the phase offset of the VSYNC events provided by
    235      * Choreographer relative to the display refresh.  For example, if Choreographer reports
    236      * that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos).
    237      */
    238     public long appVsyncOffsetNanos;
    239 
    240     /**
    241      * This is how far in advance a buffer must be queued for presentation at
    242      * a given time.  If you want a buffer to appear on the screen at
    243      * time N, you must submit the buffer before (N - bufferDeadlineNanos).
    244      */
    245     public long presentationDeadlineNanos;
    246 
    247     /**
    248      * The state of the display, such as {@link android.view.Display#STATE_ON}.
    249      */
    250     public int state;
    251 
    252     /**
    253      * The UID of the application that owns this display, or zero if it is owned by the system.
    254      * <p>
    255      * If the display is private, then only the owner can use it.
    256      * </p>
    257      */
    258     public int ownerUid;
    259 
    260     /**
    261      * The package name of the application that owns this display, or null if it is
    262      * owned by the system.
    263      * <p>
    264      * If the display is private, then only the owner can use it.
    265      * </p>
    266      */
    267     public String ownerPackageName;
    268 
    269     /**
    270      * @hide
    271      * Get current remove mode of the display - what actions should be performed with the display's
    272      * content when it is removed.
    273      *
    274      * @see Display#getRemoveMode()
    275      */
    276     // TODO (b/114338689): Remove the flag and use IWindowManager#getRemoveContentMode
    277     public int removeMode = Display.REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY;
    278 
    279     public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
    280         @Override
    281         public DisplayInfo createFromParcel(Parcel source) {
    282             return new DisplayInfo(source);
    283         }
    284 
    285         @Override
    286         public DisplayInfo[] newArray(int size) {
    287             return new DisplayInfo[size];
    288         }
    289     };
    290 
    291     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769467)
    292     public DisplayInfo() {
    293     }
    294 
    295     public DisplayInfo(DisplayInfo other) {
    296         copyFrom(other);
    297     }
    298 
    299     private DisplayInfo(Parcel source) {
    300         readFromParcel(source);
    301     }
    302 
    303     @Override
    304     public boolean equals(Object o) {
    305         return o instanceof DisplayInfo && equals((DisplayInfo)o);
    306     }
    307 
    308     public boolean equals(DisplayInfo other) {
    309         return other != null
    310                 && layerStack == other.layerStack
    311                 && flags == other.flags
    312                 && type == other.type
    313                 && displayId == other.displayId
    314                 && Objects.equals(address, other.address)
    315                 && Objects.equals(uniqueId, other.uniqueId)
    316                 && appWidth == other.appWidth
    317                 && appHeight == other.appHeight
    318                 && smallestNominalAppWidth == other.smallestNominalAppWidth
    319                 && smallestNominalAppHeight == other.smallestNominalAppHeight
    320                 && largestNominalAppWidth == other.largestNominalAppWidth
    321                 && largestNominalAppHeight == other.largestNominalAppHeight
    322                 && logicalWidth == other.logicalWidth
    323                 && logicalHeight == other.logicalHeight
    324                 && overscanLeft == other.overscanLeft
    325                 && overscanTop == other.overscanTop
    326                 && overscanRight == other.overscanRight
    327                 && overscanBottom == other.overscanBottom
    328                 && Objects.equals(displayCutout, other.displayCutout)
    329                 && rotation == other.rotation
    330                 && modeId == other.modeId
    331                 && defaultModeId == other.defaultModeId
    332                 && colorMode == other.colorMode
    333                 && Arrays.equals(supportedColorModes, other.supportedColorModes)
    334                 && Objects.equals(hdrCapabilities, other.hdrCapabilities)
    335                 && logicalDensityDpi == other.logicalDensityDpi
    336                 && physicalXDpi == other.physicalXDpi
    337                 && physicalYDpi == other.physicalYDpi
    338                 && appVsyncOffsetNanos == other.appVsyncOffsetNanos
    339                 && presentationDeadlineNanos == other.presentationDeadlineNanos
    340                 && state == other.state
    341                 && ownerUid == other.ownerUid
    342                 && Objects.equals(ownerPackageName, other.ownerPackageName)
    343                 && removeMode == other.removeMode;
    344     }
    345 
    346     @Override
    347     public int hashCode() {
    348         return 0; // don't care
    349     }
    350 
    351     public void copyFrom(DisplayInfo other) {
    352         layerStack = other.layerStack;
    353         flags = other.flags;
    354         type = other.type;
    355         displayId = other.displayId;
    356         address = other.address;
    357         name = other.name;
    358         uniqueId = other.uniqueId;
    359         appWidth = other.appWidth;
    360         appHeight = other.appHeight;
    361         smallestNominalAppWidth = other.smallestNominalAppWidth;
    362         smallestNominalAppHeight = other.smallestNominalAppHeight;
    363         largestNominalAppWidth = other.largestNominalAppWidth;
    364         largestNominalAppHeight = other.largestNominalAppHeight;
    365         logicalWidth = other.logicalWidth;
    366         logicalHeight = other.logicalHeight;
    367         overscanLeft = other.overscanLeft;
    368         overscanTop = other.overscanTop;
    369         overscanRight = other.overscanRight;
    370         overscanBottom = other.overscanBottom;
    371         displayCutout = other.displayCutout;
    372         rotation = other.rotation;
    373         modeId = other.modeId;
    374         defaultModeId = other.defaultModeId;
    375         supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
    376         colorMode = other.colorMode;
    377         supportedColorModes = Arrays.copyOf(
    378                 other.supportedColorModes, other.supportedColorModes.length);
    379         hdrCapabilities = other.hdrCapabilities;
    380         logicalDensityDpi = other.logicalDensityDpi;
    381         physicalXDpi = other.physicalXDpi;
    382         physicalYDpi = other.physicalYDpi;
    383         appVsyncOffsetNanos = other.appVsyncOffsetNanos;
    384         presentationDeadlineNanos = other.presentationDeadlineNanos;
    385         state = other.state;
    386         ownerUid = other.ownerUid;
    387         ownerPackageName = other.ownerPackageName;
    388         removeMode = other.removeMode;
    389     }
    390 
    391     public void readFromParcel(Parcel source) {
    392         layerStack = source.readInt();
    393         flags = source.readInt();
    394         type = source.readInt();
    395         displayId = source.readInt();
    396         address = source.readParcelable(null);
    397         name = source.readString();
    398         appWidth = source.readInt();
    399         appHeight = source.readInt();
    400         smallestNominalAppWidth = source.readInt();
    401         smallestNominalAppHeight = source.readInt();
    402         largestNominalAppWidth = source.readInt();
    403         largestNominalAppHeight = source.readInt();
    404         logicalWidth = source.readInt();
    405         logicalHeight = source.readInt();
    406         overscanLeft = source.readInt();
    407         overscanTop = source.readInt();
    408         overscanRight = source.readInt();
    409         overscanBottom = source.readInt();
    410         displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source);
    411         rotation = source.readInt();
    412         modeId = source.readInt();
    413         defaultModeId = source.readInt();
    414         int nModes = source.readInt();
    415         supportedModes = new Display.Mode[nModes];
    416         for (int i = 0; i < nModes; i++) {
    417             supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
    418         }
    419         colorMode = source.readInt();
    420         int nColorModes = source.readInt();
    421         supportedColorModes = new int[nColorModes];
    422         for (int i = 0; i < nColorModes; i++) {
    423             supportedColorModes[i] = source.readInt();
    424         }
    425         hdrCapabilities = source.readParcelable(null);
    426         logicalDensityDpi = source.readInt();
    427         physicalXDpi = source.readFloat();
    428         physicalYDpi = source.readFloat();
    429         appVsyncOffsetNanos = source.readLong();
    430         presentationDeadlineNanos = source.readLong();
    431         state = source.readInt();
    432         ownerUid = source.readInt();
    433         ownerPackageName = source.readString();
    434         uniqueId = source.readString();
    435         removeMode = source.readInt();
    436     }
    437 
    438     @Override
    439     public void writeToParcel(Parcel dest, int flags) {
    440         dest.writeInt(layerStack);
    441         dest.writeInt(this.flags);
    442         dest.writeInt(type);
    443         dest.writeInt(displayId);
    444         dest.writeParcelable(address, flags);
    445         dest.writeString(name);
    446         dest.writeInt(appWidth);
    447         dest.writeInt(appHeight);
    448         dest.writeInt(smallestNominalAppWidth);
    449         dest.writeInt(smallestNominalAppHeight);
    450         dest.writeInt(largestNominalAppWidth);
    451         dest.writeInt(largestNominalAppHeight);
    452         dest.writeInt(logicalWidth);
    453         dest.writeInt(logicalHeight);
    454         dest.writeInt(overscanLeft);
    455         dest.writeInt(overscanTop);
    456         dest.writeInt(overscanRight);
    457         dest.writeInt(overscanBottom);
    458         DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags);
    459         dest.writeInt(rotation);
    460         dest.writeInt(modeId);
    461         dest.writeInt(defaultModeId);
    462         dest.writeInt(supportedModes.length);
    463         for (int i = 0; i < supportedModes.length; i++) {
    464             supportedModes[i].writeToParcel(dest, flags);
    465         }
    466         dest.writeInt(colorMode);
    467         dest.writeInt(supportedColorModes.length);
    468         for (int i = 0; i < supportedColorModes.length; i++) {
    469             dest.writeInt(supportedColorModes[i]);
    470         }
    471         dest.writeParcelable(hdrCapabilities, flags);
    472         dest.writeInt(logicalDensityDpi);
    473         dest.writeFloat(physicalXDpi);
    474         dest.writeFloat(physicalYDpi);
    475         dest.writeLong(appVsyncOffsetNanos);
    476         dest.writeLong(presentationDeadlineNanos);
    477         dest.writeInt(state);
    478         dest.writeInt(ownerUid);
    479         dest.writeString(ownerPackageName);
    480         dest.writeString(uniqueId);
    481         dest.writeInt(removeMode);
    482     }
    483 
    484     @Override
    485     public int describeContents() {
    486         return 0;
    487     }
    488 
    489     public Display.Mode getMode() {
    490         return findMode(modeId);
    491     }
    492 
    493     public Display.Mode getDefaultMode() {
    494         return findMode(defaultModeId);
    495     }
    496 
    497     private Display.Mode findMode(int id) {
    498         for (int i = 0; i < supportedModes.length; i++) {
    499             if (supportedModes[i].getModeId() == id) {
    500                 return supportedModes[i];
    501             }
    502         }
    503         throw new IllegalStateException("Unable to locate mode " + id);
    504     }
    505 
    506     /**
    507      * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable
    508      * mode could be found.
    509      */
    510     public int findDefaultModeByRefreshRate(float refreshRate) {
    511         Display.Mode[] modes = supportedModes;
    512         Display.Mode defaultMode = getDefaultMode();
    513         for (int i = 0; i < modes.length; i++) {
    514             if (modes[i].matches(
    515                     defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) {
    516                 return modes[i].getModeId();
    517             }
    518         }
    519         return 0;
    520     }
    521 
    522     /**
    523      * Returns the list of supported refresh rates in the default mode.
    524      */
    525     public float[] getDefaultRefreshRates() {
    526         Display.Mode[] modes = supportedModes;
    527         ArraySet<Float> rates = new ArraySet<>();
    528         Display.Mode defaultMode = getDefaultMode();
    529         for (int i = 0; i < modes.length; i++) {
    530             Display.Mode mode = modes[i];
    531             if (mode.getPhysicalWidth() == defaultMode.getPhysicalWidth()
    532                     && mode.getPhysicalHeight() == defaultMode.getPhysicalHeight()) {
    533                 rates.add(mode.getRefreshRate());
    534             }
    535         }
    536         float[] result = new float[rates.size()];
    537         int i = 0;
    538         for (Float rate : rates) {
    539             result[i++] = rate;
    540         }
    541         return result;
    542     }
    543 
    544     public void getAppMetrics(DisplayMetrics outMetrics) {
    545         getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
    546     }
    547 
    548     public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) {
    549         getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(),
    550                 displayAdjustments.getConfiguration(), appWidth, appHeight);
    551     }
    552 
    553     public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci,
    554             Configuration configuration) {
    555         getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight);
    556     }
    557 
    558     public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
    559             Configuration configuration) {
    560         getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight);
    561     }
    562 
    563     public int getNaturalWidth() {
    564         return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
    565                 logicalWidth : logicalHeight;
    566     }
    567 
    568     public int getNaturalHeight() {
    569         return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
    570                 logicalHeight : logicalWidth;
    571     }
    572 
    573     public boolean isHdr() {
    574         int[] types = hdrCapabilities != null ? hdrCapabilities.getSupportedHdrTypes() : null;
    575         return types != null && types.length > 0;
    576     }
    577 
    578     public boolean isWideColorGamut() {
    579         for (int colorMode : supportedColorModes) {
    580             if (colorMode == Display.COLOR_MODE_DCI_P3 || colorMode > Display.COLOR_MODE_SRGB) {
    581                 return true;
    582             }
    583         }
    584         return false;
    585     }
    586 
    587     /**
    588      * Returns true if the specified UID has access to this display.
    589      */
    590     public boolean hasAccess(int uid) {
    591         return Display.hasAccess(uid, flags, ownerUid, displayId);
    592     }
    593 
    594     private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
    595             Configuration configuration, int width, int height) {
    596         outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
    597         outMetrics.density = outMetrics.noncompatDensity =
    598                 logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
    599         outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
    600         outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
    601         outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
    602 
    603         final Rect appBounds = configuration != null
    604                 ? configuration.windowConfiguration.getAppBounds() : null;
    605         width = appBounds != null ? appBounds.width() : width;
    606         height = appBounds != null ? appBounds.height() : height;
    607 
    608         outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
    609         outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
    610 
    611         if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
    612             compatInfo.applyToDisplayMetrics(outMetrics);
    613         }
    614     }
    615 
    616     // For debugging purposes
    617     @Override
    618     public String toString() {
    619         StringBuilder sb = new StringBuilder();
    620         sb.append("DisplayInfo{\"");
    621         sb.append(name);
    622         sb.append(", displayId ");
    623         sb.append(displayId);
    624         sb.append("\", uniqueId \"");
    625         sb.append(uniqueId);
    626         sb.append("\", app ");
    627         sb.append(appWidth);
    628         sb.append(" x ");
    629         sb.append(appHeight);
    630         sb.append(", real ");
    631         sb.append(logicalWidth);
    632         sb.append(" x ");
    633         sb.append(logicalHeight);
    634         if (overscanLeft != 0 || overscanTop != 0 || overscanRight != 0 || overscanBottom != 0) {
    635             sb.append(", overscan (");
    636             sb.append(overscanLeft);
    637             sb.append(",");
    638             sb.append(overscanTop);
    639             sb.append(",");
    640             sb.append(overscanRight);
    641             sb.append(",");
    642             sb.append(overscanBottom);
    643             sb.append(")");
    644         }
    645         sb.append(", largest app ");
    646         sb.append(largestNominalAppWidth);
    647         sb.append(" x ");
    648         sb.append(largestNominalAppHeight);
    649         sb.append(", smallest app ");
    650         sb.append(smallestNominalAppWidth);
    651         sb.append(" x ");
    652         sb.append(smallestNominalAppHeight);
    653         sb.append(", mode ");
    654         sb.append(modeId);
    655         sb.append(", defaultMode ");
    656         sb.append(defaultModeId);
    657         sb.append(", modes ");
    658         sb.append(Arrays.toString(supportedModes));
    659         sb.append(", colorMode ");
    660         sb.append(colorMode);
    661         sb.append(", supportedColorModes ");
    662         sb.append(Arrays.toString(supportedColorModes));
    663         sb.append(", hdrCapabilities ");
    664         sb.append(hdrCapabilities);
    665         sb.append(", rotation ");
    666         sb.append(rotation);
    667         sb.append(", density ");
    668         sb.append(logicalDensityDpi);
    669         sb.append(" (");
    670         sb.append(physicalXDpi);
    671         sb.append(" x ");
    672         sb.append(physicalYDpi);
    673         sb.append(") dpi, layerStack ");
    674         sb.append(layerStack);
    675         sb.append(", appVsyncOff ");
    676         sb.append(appVsyncOffsetNanos);
    677         sb.append(", presDeadline ");
    678         sb.append(presentationDeadlineNanos);
    679         sb.append(", type ");
    680         sb.append(Display.typeToString(type));
    681         if (address != null) {
    682             sb.append(", address ").append(address);
    683         }
    684         sb.append(", state ");
    685         sb.append(Display.stateToString(state));
    686         if (ownerUid != 0 || ownerPackageName != null) {
    687             sb.append(", owner ").append(ownerPackageName);
    688             sb.append(" (uid ").append(ownerUid).append(")");
    689         }
    690         sb.append(flagsToString(flags));
    691         sb.append(", removeMode ");
    692         sb.append(removeMode);
    693         sb.append("}");
    694         return sb.toString();
    695     }
    696 
    697     /**
    698      * Write to a protocol buffer output stream.
    699      * Protocol buffer message definition at {@link android.view.DisplayInfoProto}
    700      *
    701      * @param protoOutputStream Stream to write the Rect object to.
    702      * @param fieldId           Field Id of the DisplayInfoProto as defined in the parent message
    703      */
    704     public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
    705         final long token = protoOutputStream.start(fieldId);
    706         protoOutputStream.write(LOGICAL_WIDTH, logicalWidth);
    707         protoOutputStream.write(LOGICAL_HEIGHT, logicalHeight);
    708         protoOutputStream.write(APP_WIDTH, appWidth);
    709         protoOutputStream.write(APP_HEIGHT, appHeight);
    710         protoOutputStream.write(NAME, name);
    711         protoOutputStream.end(token);
    712     }
    713 
    714     private static String flagsToString(int flags) {
    715         StringBuilder result = new StringBuilder();
    716         if ((flags & Display.FLAG_SECURE) != 0) {
    717             result.append(", FLAG_SECURE");
    718         }
    719         if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
    720             result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
    721         }
    722         if ((flags & Display.FLAG_PRIVATE) != 0) {
    723             result.append(", FLAG_PRIVATE");
    724         }
    725         if ((flags & Display.FLAG_PRESENTATION) != 0) {
    726             result.append(", FLAG_PRESENTATION");
    727         }
    728         if ((flags & Display.FLAG_SCALING_DISABLED) != 0) {
    729             result.append(", FLAG_SCALING_DISABLED");
    730         }
    731         if ((flags & Display.FLAG_ROUND) != 0) {
    732             result.append(", FLAG_ROUND");
    733         }
    734         return result.toString();
    735     }
    736 }
    737