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