Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2017 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.app;
     18 
     19 import static android.app.ActivityThread.isSystem;
     20 import static android.app.WindowConfigurationProto.ACTIVITY_TYPE;
     21 import static android.app.WindowConfigurationProto.APP_BOUNDS;
     22 import static android.app.WindowConfigurationProto.BOUNDS;
     23 import static android.app.WindowConfigurationProto.WINDOWING_MODE;
     24 import static android.view.Surface.rotationToString;
     25 
     26 import android.annotation.IntDef;
     27 import android.annotation.NonNull;
     28 import android.annotation.TestApi;
     29 import android.content.res.Configuration;
     30 import android.graphics.Rect;
     31 import android.os.Parcel;
     32 import android.os.Parcelable;
     33 import android.util.proto.ProtoInputStream;
     34 import android.util.proto.ProtoOutputStream;
     35 import android.util.proto.WireTypeMismatchException;
     36 import android.view.DisplayInfo;
     37 
     38 import java.io.IOException;
     39 
     40 /**
     41  * Class that contains windowing configuration/state for other objects that contain windows directly
     42  * or indirectly. E.g. Activities, Task, Displays, ...
     43  * The test class is {@link com.android.server.wm.WindowConfigurationTests} which must be kept
     44  * up-to-date and ran anytime changes are made to this class.
     45  * @hide
     46  */
     47 @TestApi
     48 public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {
     49     /**
     50      * bounds that can differ from app bounds, which may include things such as insets.
     51      *
     52      * TODO: Investigate combining with {@link mAppBounds}. Can the latter be a product of the
     53      * former?
     54      */
     55     private Rect mBounds = new Rect();
     56 
     57     /**
     58      * {@link android.graphics.Rect} defining app bounds. The dimensions override usages of
     59      * {@link DisplayInfo#appHeight} and {@link DisplayInfo#appWidth} and mirrors these values at
     60      * the display level. Lower levels can override these values to provide custom bounds to enforce
     61      * features such as a max aspect ratio.
     62      */
     63     private Rect mAppBounds;
     64 
     65     /**
     66      * The current rotation of this window container relative to the default
     67      * orientation of the display it is on (regardless of how deep in the hierarchy
     68      * it is). It is used by the configuration hierarchy to apply rotation-dependent
     69      * policy during bounds calculation.
     70      */
     71     private int mRotation = ROTATION_UNDEFINED;
     72 
     73     /** Rotation is not defined, use the parent containers rotation. */
     74     public static final int ROTATION_UNDEFINED = -1;
     75 
     76     /** The current windowing mode of the configuration. */
     77     private @WindowingMode int mWindowingMode;
     78 
     79     /** The display windowing mode of the configuration */
     80     private @WindowingMode int mDisplayWindowingMode;
     81 
     82     /** Windowing mode is currently not defined. */
     83     public static final int WINDOWING_MODE_UNDEFINED = 0;
     84     /** Occupies the full area of the screen or the parent container. */
     85     public static final int WINDOWING_MODE_FULLSCREEN = 1;
     86     /** Always on-top (always visible). of other siblings in its parent container. */
     87     public static final int WINDOWING_MODE_PINNED = 2;
     88     /** The primary container driving the screen to be in split-screen mode. */
     89     public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;
     90     /**
     91      * The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
     92      * split-screen mode.
     93      * NOTE: Containers launched with the windowing mode with APIs like
     94      * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in
     95      * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing
     96      * mode
     97      * @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
     98      */
     99     public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
    100     /**
    101      * Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage
    102      * points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container
    103      * will launch into fullscreen or split-screen secondary depending on if the device is currently
    104      * in fullscreen mode or split-screen mode.
    105      */
    106     public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY =
    107             WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
    108     /** Can be freely resized within its parent container. */
    109     public static final int WINDOWING_MODE_FREEFORM = 5;
    110 
    111     /** @hide */
    112     @IntDef(prefix = { "WINDOWING_MODE_" }, value = {
    113             WINDOWING_MODE_UNDEFINED,
    114             WINDOWING_MODE_FULLSCREEN,
    115             WINDOWING_MODE_PINNED,
    116             WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
    117             WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
    118             WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY,
    119             WINDOWING_MODE_FREEFORM,
    120     })
    121     public @interface WindowingMode {}
    122 
    123     /** The current activity type of the configuration. */
    124     private @ActivityType int mActivityType;
    125 
    126     /** Activity type is currently not defined. */
    127     public static final int ACTIVITY_TYPE_UNDEFINED = 0;
    128     /** Standard activity type. Nothing special about the activity... */
    129     public static final int ACTIVITY_TYPE_STANDARD = 1;
    130     /** Home/Launcher activity type. */
    131     public static final int ACTIVITY_TYPE_HOME = 2;
    132     /** Recents/Overview activity type. There is only one activity with this type in the system. */
    133     public static final int ACTIVITY_TYPE_RECENTS = 3;
    134     /** Assistant activity type. */
    135     public static final int ACTIVITY_TYPE_ASSISTANT = 4;
    136 
    137     /** @hide */
    138     @IntDef(prefix = { "ACTIVITY_TYPE_" }, value = {
    139             ACTIVITY_TYPE_UNDEFINED,
    140             ACTIVITY_TYPE_STANDARD,
    141             ACTIVITY_TYPE_HOME,
    142             ACTIVITY_TYPE_RECENTS,
    143             ACTIVITY_TYPE_ASSISTANT,
    144     })
    145     public @interface ActivityType {}
    146 
    147     /** The current always on top status of the configuration. */
    148     private @AlwaysOnTop int mAlwaysOnTop;
    149 
    150     /** Always on top is currently not defined. */
    151     private static final int ALWAYS_ON_TOP_UNDEFINED = 0;
    152     /** Always on top is currently on for this configuration. */
    153     private static final int ALWAYS_ON_TOP_ON = 1;
    154     /** Always on top is currently off for this configuration. */
    155     private static final int ALWAYS_ON_TOP_OFF = 2;
    156 
    157     /** @hide */
    158     @IntDef(prefix = { "ALWAYS_ON_TOP_" }, value = {
    159             ALWAYS_ON_TOP_UNDEFINED,
    160             ALWAYS_ON_TOP_ON,
    161             ALWAYS_ON_TOP_OFF,
    162     })
    163     private @interface AlwaysOnTop {}
    164 
    165     /** Bit that indicates that the {@link #mBounds} changed.
    166      * @hide */
    167     public static final int WINDOW_CONFIG_BOUNDS = 1 << 0;
    168     /** Bit that indicates that the {@link #mAppBounds} changed.
    169      * @hide */
    170     public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 1;
    171     /** Bit that indicates that the {@link #mWindowingMode} changed.
    172      * @hide */
    173     public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 2;
    174     /** Bit that indicates that the {@link #mActivityType} changed.
    175      * @hide */
    176     public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3;
    177     /** Bit that indicates that the {@link #mAlwaysOnTop} changed.
    178      * @hide */
    179     public static final int WINDOW_CONFIG_ALWAYS_ON_TOP = 1 << 4;
    180     /** Bit that indicates that the {@link #mRotation} changed.
    181      * @hide */
    182     public static final int WINDOW_CONFIG_ROTATION = 1 << 5;
    183     /** Bit that indicates that the {@link #mDisplayWindowingMode} changed.
    184      * @hide */
    185     public static final int WINDOW_CONFIG_DISPLAY_WINDOWING_MODE = 1 << 6;
    186 
    187     /** @hide */
    188     @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = {
    189             WINDOW_CONFIG_BOUNDS,
    190             WINDOW_CONFIG_APP_BOUNDS,
    191             WINDOW_CONFIG_WINDOWING_MODE,
    192             WINDOW_CONFIG_ACTIVITY_TYPE,
    193             WINDOW_CONFIG_ALWAYS_ON_TOP,
    194             WINDOW_CONFIG_ROTATION,
    195             WINDOW_CONFIG_DISPLAY_WINDOWING_MODE,
    196     })
    197     public @interface WindowConfig {}
    198 
    199     /** @hide */
    200     public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5;
    201 
    202     public WindowConfiguration() {
    203         unset();
    204     }
    205 
    206     /** @hide */
    207     public WindowConfiguration(WindowConfiguration configuration) {
    208         setTo(configuration);
    209     }
    210 
    211     private WindowConfiguration(Parcel in) {
    212         readFromParcel(in);
    213     }
    214 
    215     @Override
    216     public void writeToParcel(Parcel dest, int flags) {
    217         dest.writeParcelable(mBounds, flags);
    218         dest.writeParcelable(mAppBounds, flags);
    219         dest.writeInt(mWindowingMode);
    220         dest.writeInt(mActivityType);
    221         dest.writeInt(mAlwaysOnTop);
    222         dest.writeInt(mRotation);
    223         dest.writeInt(mDisplayWindowingMode);
    224     }
    225 
    226     private void readFromParcel(Parcel source) {
    227         mBounds = source.readParcelable(Rect.class.getClassLoader());
    228         mAppBounds = source.readParcelable(Rect.class.getClassLoader());
    229         mWindowingMode = source.readInt();
    230         mActivityType = source.readInt();
    231         mAlwaysOnTop = source.readInt();
    232         mRotation = source.readInt();
    233         mDisplayWindowingMode = source.readInt();
    234     }
    235 
    236     @Override
    237     public int describeContents() {
    238         return 0;
    239     }
    240 
    241     /** @hide */
    242     public static final @android.annotation.NonNull Creator<WindowConfiguration> CREATOR = new Creator<WindowConfiguration>() {
    243         @Override
    244         public WindowConfiguration createFromParcel(Parcel in) {
    245             return new WindowConfiguration(in);
    246         }
    247 
    248         @Override
    249         public WindowConfiguration[] newArray(int size) {
    250             return new WindowConfiguration[size];
    251         }
    252     };
    253 
    254     /**
    255      * Sets the bounds to the provided {@link Rect}.
    256      * @param rect the new bounds value.
    257      */
    258     public void setBounds(Rect rect) {
    259         if (rect == null) {
    260             mBounds.setEmpty();
    261             return;
    262         }
    263 
    264         mBounds.set(rect);
    265     }
    266 
    267     /**
    268      * Set {@link #mAppBounds} to the input Rect.
    269      * @param rect The rect value to set {@link #mAppBounds} to.
    270      * @see #getAppBounds()
    271      */
    272     public void setAppBounds(Rect rect) {
    273         if (rect == null) {
    274             mAppBounds = null;
    275             return;
    276         }
    277 
    278         setAppBounds(rect.left, rect.top, rect.right, rect.bottom);
    279     }
    280 
    281 
    282 
    283     /**
    284      * Sets whether this window should be always on top.
    285      * @param alwaysOnTop {@code true} to set window always on top, otherwise {@code false}
    286      * @hide
    287      */
    288     public void setAlwaysOnTop(boolean alwaysOnTop) {
    289         mAlwaysOnTop = alwaysOnTop ? ALWAYS_ON_TOP_ON : ALWAYS_ON_TOP_OFF;
    290     }
    291 
    292     private void setAlwaysOnTop(@AlwaysOnTop int alwaysOnTop) {
    293         mAlwaysOnTop = alwaysOnTop;
    294     }
    295 
    296     /**
    297      * @see #setAppBounds(Rect)
    298      * @see #getAppBounds()
    299      * @hide
    300      */
    301     public void setAppBounds(int left, int top, int right, int bottom) {
    302         if (mAppBounds == null) {
    303             mAppBounds = new Rect();
    304         }
    305 
    306         mAppBounds.set(left, top, right, bottom);
    307     }
    308 
    309     /** @see #setAppBounds(Rect) */
    310     public Rect getAppBounds() {
    311         return mAppBounds;
    312     }
    313 
    314     /** @see #setBounds(Rect) */
    315     public Rect getBounds() {
    316         return mBounds;
    317     }
    318 
    319     public int getRotation() {
    320         return mRotation;
    321     }
    322 
    323     public void setRotation(int rotation) {
    324         mRotation = rotation;
    325     }
    326 
    327     public void setWindowingMode(@WindowingMode int windowingMode) {
    328         mWindowingMode = windowingMode;
    329     }
    330 
    331     @WindowingMode
    332     public int getWindowingMode() {
    333         return mWindowingMode;
    334     }
    335 
    336     /** @hide */
    337     public void setDisplayWindowingMode(@WindowingMode int windowingMode) {
    338         mDisplayWindowingMode = windowingMode;
    339     }
    340 
    341 
    342     public void setActivityType(@ActivityType int activityType) {
    343         if (mActivityType == activityType) {
    344             return;
    345         }
    346 
    347         // Error check within system server that we are not changing activity type which can be
    348         // dangerous. It is okay for things to change in the application process as it doesn't
    349         // affect how other things is the system is managed.
    350         if (isSystem()
    351                 && mActivityType != ACTIVITY_TYPE_UNDEFINED
    352                 && activityType != ACTIVITY_TYPE_UNDEFINED) {
    353             throw new IllegalStateException("Can't change activity type once set: " + this
    354                     + " activityType=" + activityTypeToString(activityType));
    355         }
    356         mActivityType = activityType;
    357     }
    358 
    359     @ActivityType
    360     public int getActivityType() {
    361         return mActivityType;
    362     }
    363 
    364     public void setTo(WindowConfiguration other) {
    365         setBounds(other.mBounds);
    366         setAppBounds(other.mAppBounds);
    367         setWindowingMode(other.mWindowingMode);
    368         setActivityType(other.mActivityType);
    369         setAlwaysOnTop(other.mAlwaysOnTop);
    370         setRotation(other.mRotation);
    371         setDisplayWindowingMode(other.mDisplayWindowingMode);
    372     }
    373 
    374     /** Set this object to completely undefined.
    375      * @hide */
    376     public void unset() {
    377         setToDefaults();
    378     }
    379 
    380     /** @hide */
    381     public void setToDefaults() {
    382         setAppBounds(null);
    383         setBounds(null);
    384         setWindowingMode(WINDOWING_MODE_UNDEFINED);
    385         setActivityType(ACTIVITY_TYPE_UNDEFINED);
    386         setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED);
    387         setRotation(ROTATION_UNDEFINED);
    388         setDisplayWindowingMode(WINDOWING_MODE_UNDEFINED);
    389     }
    390 
    391     /**
    392      * Copies the fields from delta into this Configuration object, keeping
    393      * track of which ones have changed. Any undefined fields in {@code delta}
    394      * are ignored and not copied in to the current Configuration.
    395      *
    396      * @return a bit mask of the changed fields, as per {@link #diff}
    397      * @hide
    398      */
    399     public @WindowConfig int updateFrom(@NonNull WindowConfiguration delta) {
    400         int changed = 0;
    401         // Only allow override if bounds is not empty
    402         if (!delta.mBounds.isEmpty() && !delta.mBounds.equals(mBounds)) {
    403             changed |= WINDOW_CONFIG_BOUNDS;
    404             setBounds(delta.mBounds);
    405         }
    406         if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) {
    407             changed |= WINDOW_CONFIG_APP_BOUNDS;
    408             setAppBounds(delta.mAppBounds);
    409         }
    410         if (delta.mWindowingMode != WINDOWING_MODE_UNDEFINED
    411                 && mWindowingMode != delta.mWindowingMode) {
    412             changed |= WINDOW_CONFIG_WINDOWING_MODE;
    413             setWindowingMode(delta.mWindowingMode);
    414         }
    415         if (delta.mActivityType != ACTIVITY_TYPE_UNDEFINED
    416                 && mActivityType != delta.mActivityType) {
    417             changed |= WINDOW_CONFIG_ACTIVITY_TYPE;
    418             setActivityType(delta.mActivityType);
    419         }
    420         if (delta.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED
    421                 && mAlwaysOnTop != delta.mAlwaysOnTop) {
    422             changed |= WINDOW_CONFIG_ALWAYS_ON_TOP;
    423             setAlwaysOnTop(delta.mAlwaysOnTop);
    424         }
    425         if (delta.mRotation != ROTATION_UNDEFINED && delta.mRotation != mRotation) {
    426             changed |= WINDOW_CONFIG_ROTATION;
    427             setRotation(delta.mRotation);
    428         }
    429         if (delta.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED
    430                 && mDisplayWindowingMode != delta.mDisplayWindowingMode) {
    431             changed |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE;
    432             setDisplayWindowingMode(delta.mDisplayWindowingMode);
    433         }
    434         return changed;
    435     }
    436 
    437     /**
    438      * Return a bit mask of the differences between this Configuration object and the given one.
    439      * Does not change the values of either. Any undefined fields in <var>other</var> are ignored.
    440      * @param other The configuration to diff against.
    441      * @param compareUndefined If undefined values should be compared.
    442      * @return Returns a bit mask indicating which configuration
    443      * values has changed, containing any combination of {@link WindowConfig} flags.
    444      *
    445      * @see Configuration#diff(Configuration)
    446      * @hide
    447      */
    448     public @WindowConfig long diff(WindowConfiguration other, boolean compareUndefined) {
    449         long changes = 0;
    450 
    451         if (!mBounds.equals(other.mBounds)) {
    452             changes |= WINDOW_CONFIG_BOUNDS;
    453         }
    454 
    455         // Make sure that one of the values is not null and that they are not equal.
    456         if ((compareUndefined || other.mAppBounds != null)
    457                 && mAppBounds != other.mAppBounds
    458                 && (mAppBounds == null || !mAppBounds.equals(other.mAppBounds))) {
    459             changes |= WINDOW_CONFIG_APP_BOUNDS;
    460         }
    461 
    462         if ((compareUndefined || other.mWindowingMode != WINDOWING_MODE_UNDEFINED)
    463                 && mWindowingMode != other.mWindowingMode) {
    464             changes |= WINDOW_CONFIG_WINDOWING_MODE;
    465         }
    466 
    467         if ((compareUndefined || other.mActivityType != ACTIVITY_TYPE_UNDEFINED)
    468                 && mActivityType != other.mActivityType) {
    469             changes |= WINDOW_CONFIG_ACTIVITY_TYPE;
    470         }
    471 
    472         if ((compareUndefined || other.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED)
    473                 && mAlwaysOnTop != other.mAlwaysOnTop) {
    474             changes |= WINDOW_CONFIG_ALWAYS_ON_TOP;
    475         }
    476 
    477         if ((compareUndefined || other.mRotation != ROTATION_UNDEFINED)
    478                 && mRotation != other.mRotation) {
    479             changes |= WINDOW_CONFIG_ROTATION;
    480         }
    481 
    482         if ((compareUndefined || other.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED)
    483                 && mDisplayWindowingMode != other.mDisplayWindowingMode) {
    484             changes |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE;
    485         }
    486 
    487         return changes;
    488     }
    489 
    490     @Override
    491     public int compareTo(WindowConfiguration that) {
    492         int n = 0;
    493         if (mAppBounds == null && that.mAppBounds != null) {
    494             return 1;
    495         } else if (mAppBounds != null && that.mAppBounds == null) {
    496             return -1;
    497         } else if (mAppBounds != null && that.mAppBounds != null) {
    498             n = mAppBounds.left - that.mAppBounds.left;
    499             if (n != 0) return n;
    500             n = mAppBounds.top - that.mAppBounds.top;
    501             if (n != 0) return n;
    502             n = mAppBounds.right - that.mAppBounds.right;
    503             if (n != 0) return n;
    504             n = mAppBounds.bottom - that.mAppBounds.bottom;
    505             if (n != 0) return n;
    506         }
    507 
    508         n = mBounds.left - that.mBounds.left;
    509         if (n != 0) return n;
    510         n = mBounds.top - that.mBounds.top;
    511         if (n != 0) return n;
    512         n = mBounds.right - that.mBounds.right;
    513         if (n != 0) return n;
    514         n = mBounds.bottom - that.mBounds.bottom;
    515         if (n != 0) return n;
    516 
    517         n = mWindowingMode - that.mWindowingMode;
    518         if (n != 0) return n;
    519         n = mActivityType - that.mActivityType;
    520         if (n != 0) return n;
    521         n = mAlwaysOnTop - that.mAlwaysOnTop;
    522         if (n != 0) return n;
    523         n = mRotation - that.mRotation;
    524         if (n != 0) return n;
    525         n = mDisplayWindowingMode - that.mDisplayWindowingMode;
    526         if (n != 0) return n;
    527 
    528         // if (n != 0) return n;
    529         return n;
    530     }
    531 
    532     /** @hide */
    533     @Override
    534     public boolean equals(Object that) {
    535         if (that == null) return false;
    536         if (that == this) return true;
    537         if (!(that instanceof WindowConfiguration)) {
    538             return false;
    539         }
    540         return this.compareTo((WindowConfiguration) that) == 0;
    541     }
    542 
    543     /** @hide */
    544     @Override
    545     public int hashCode() {
    546         int result = 0;
    547         if (mAppBounds != null) {
    548             result = 31 * result + mAppBounds.hashCode();
    549         }
    550         result = 31 * result + mBounds.hashCode();
    551 
    552         result = 31 * result + mWindowingMode;
    553         result = 31 * result + mActivityType;
    554         result = 31 * result + mAlwaysOnTop;
    555         result = 31 * result + mRotation;
    556         result = 31 * result + mDisplayWindowingMode;
    557         return result;
    558     }
    559 
    560     /** @hide */
    561     @Override
    562     public String toString() {
    563         return "{ mBounds=" + mBounds
    564                 + " mAppBounds=" + mAppBounds
    565                 + " mWindowingMode=" + windowingModeToString(mWindowingMode)
    566                 + " mDisplayWindowingMode=" + windowingModeToString(mDisplayWindowingMode)
    567                 + " mActivityType=" + activityTypeToString(mActivityType)
    568                 + " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)
    569                 + " mRotation=" + (mRotation == ROTATION_UNDEFINED
    570                         ? "undefined" : rotationToString(mRotation))
    571                 + "}";
    572     }
    573 
    574     /**
    575      * Write to a protocol buffer output stream.
    576      * Protocol buffer message definition at {@link android.app.WindowConfigurationProto}
    577      *
    578      * @param protoOutputStream Stream to write the WindowConfiguration object to.
    579      * @param fieldId           Field Id of the WindowConfiguration as defined in the parent message
    580      * @hide
    581      */
    582     public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
    583         final long token = protoOutputStream.start(fieldId);
    584         if (mAppBounds != null) {
    585             mAppBounds.writeToProto(protoOutputStream, APP_BOUNDS);
    586         }
    587         protoOutputStream.write(WINDOWING_MODE, mWindowingMode);
    588         protoOutputStream.write(ACTIVITY_TYPE, mActivityType);
    589         if (mBounds != null) {
    590             mBounds.writeToProto(protoOutputStream, BOUNDS);
    591         }
    592         protoOutputStream.end(token);
    593     }
    594 
    595     /**
    596      * Read from a protocol buffer input stream.
    597      * Protocol buffer message definition at {@link android.app.WindowConfigurationProto}
    598      *
    599      * @param proto   Stream to read the WindowConfiguration object from.
    600      * @param fieldId Field Id of the WindowConfiguration as defined in the parent message
    601      * @hide
    602      */
    603     public void readFromProto(ProtoInputStream proto, long fieldId)
    604             throws IOException, WireTypeMismatchException {
    605         final long token = proto.start(fieldId);
    606         try {
    607             while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    608                 switch (proto.getFieldNumber()) {
    609                     case (int) APP_BOUNDS:
    610                         mAppBounds = new Rect();
    611                         mAppBounds.readFromProto(proto, APP_BOUNDS);
    612                         break;
    613                     case (int) BOUNDS:
    614                         mBounds = new Rect();
    615                         mBounds.readFromProto(proto, BOUNDS);
    616                         break;
    617                     case (int) WINDOWING_MODE:
    618                         mWindowingMode = proto.readInt(WINDOWING_MODE);
    619                         break;
    620                     case (int) ACTIVITY_TYPE:
    621                         mActivityType = proto.readInt(ACTIVITY_TYPE);
    622                         break;
    623                 }
    624             }
    625         } finally {
    626             // Let caller handle any exceptions
    627             proto.end(token);
    628         }
    629     }
    630 
    631     /**
    632      * Returns true if the activities associated with this window configuration display a shadow
    633      * around their border.
    634      * @hide
    635      */
    636     public boolean hasWindowShadow() {
    637         return tasksAreFloating();
    638     }
    639 
    640     /**
    641      * Returns true if the activities associated with this window configuration display a decor
    642      * view.
    643      * @hide
    644      */
    645     public boolean hasWindowDecorCaption() {
    646         return mActivityType == ACTIVITY_TYPE_STANDARD && (mWindowingMode == WINDOWING_MODE_FREEFORM
    647                 || mDisplayWindowingMode == WINDOWING_MODE_FREEFORM);
    648     }
    649 
    650     /**
    651      * Returns true if the tasks associated with this window configuration can be resized
    652      * independently of their parent container.
    653      * @hide
    654      */
    655     public boolean canResizeTask() {
    656         return mWindowingMode == WINDOWING_MODE_FREEFORM;
    657     }
    658 
    659     /** Returns true if the task bounds should persist across power cycles.
    660      * @hide */
    661     public boolean persistTaskBounds() {
    662         return mWindowingMode == WINDOWING_MODE_FREEFORM;
    663     }
    664 
    665     /**
    666      * Returns true if the tasks associated with this window configuration are floating.
    667      * Floating tasks are laid out differently as they are allowed to extend past the display bounds
    668      * without overscan insets.
    669      * @hide
    670      */
    671     public boolean tasksAreFloating() {
    672         return isFloating(mWindowingMode);
    673     }
    674 
    675     /**
    676      * Returns true if the windowingMode represents a floating window.
    677      * @hide
    678      */
    679     public static boolean isFloating(int windowingMode) {
    680         return windowingMode == WINDOWING_MODE_FREEFORM || windowingMode == WINDOWING_MODE_PINNED;
    681     }
    682 
    683     /**
    684      * Returns true if the windowingMode represents a split window.
    685      * @hide
    686      */
    687     public static boolean isSplitScreenWindowingMode(int windowingMode) {
    688         return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
    689                 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
    690     }
    691 
    692     /**
    693      * Returns true if the windows associated with this window configuration can receive input keys.
    694      * @hide
    695      */
    696     public boolean canReceiveKeys() {
    697         return mWindowingMode != WINDOWING_MODE_PINNED;
    698     }
    699 
    700     /**
    701      * Returns true if the container associated with this window configuration is always-on-top of
    702      * its siblings.
    703      * @hide
    704      */
    705     public boolean isAlwaysOnTop() {
    706         return mWindowingMode == WINDOWING_MODE_PINNED
    707                 || (mWindowingMode == WINDOWING_MODE_FREEFORM && mAlwaysOnTop == ALWAYS_ON_TOP_ON);
    708     }
    709 
    710     /**
    711      * Returns true if any visible windows belonging to apps with this window configuration should
    712      * be kept on screen when the app is killed due to something like the low memory killer.
    713      * @hide
    714      */
    715     public boolean keepVisibleDeadAppWindowOnScreen() {
    716         return mWindowingMode != WINDOWING_MODE_PINNED;
    717     }
    718 
    719     /**
    720      * Returns true if the backdrop on the client side should match the frame of the window.
    721      * Returns false, if the backdrop should be fullscreen.
    722      * @hide
    723      */
    724     public boolean useWindowFrameForBackdrop() {
    725         return mWindowingMode == WINDOWING_MODE_FREEFORM || mWindowingMode == WINDOWING_MODE_PINNED;
    726     }
    727 
    728     /**
    729      * Returns true if this container may be scaled without resizing, and windows within may need
    730      * to be configured as such.
    731      * @hide
    732      */
    733     public boolean windowsAreScaleable() {
    734         return mWindowingMode == WINDOWING_MODE_PINNED;
    735     }
    736 
    737     /**
    738      * Returns true if windows in this container should be given move animations by default.
    739      * @hide
    740      */
    741     public boolean hasMovementAnimations() {
    742         return mWindowingMode != WINDOWING_MODE_PINNED;
    743     }
    744 
    745     /**
    746      * Returns true if this container can be put in either
    747      * {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
    748      * {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on its current state.
    749      * @hide
    750      */
    751     public boolean supportSplitScreenWindowingMode() {
    752         return supportSplitScreenWindowingMode(mActivityType);
    753     }
    754 
    755     /** @hide */
    756     public static boolean supportSplitScreenWindowingMode(int activityType) {
    757         return activityType != ACTIVITY_TYPE_ASSISTANT;
    758     }
    759 
    760     /** @hide */
    761     public static String windowingModeToString(@WindowingMode int windowingMode) {
    762         switch (windowingMode) {
    763             case WINDOWING_MODE_UNDEFINED: return "undefined";
    764             case WINDOWING_MODE_FULLSCREEN: return "fullscreen";
    765             case WINDOWING_MODE_PINNED: return "pinned";
    766             case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary";
    767             case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary";
    768             case WINDOWING_MODE_FREEFORM: return "freeform";
    769         }
    770         return String.valueOf(windowingMode);
    771     }
    772 
    773     /** @hide */
    774     public static String activityTypeToString(@ActivityType int applicationType) {
    775         switch (applicationType) {
    776             case ACTIVITY_TYPE_UNDEFINED: return "undefined";
    777             case ACTIVITY_TYPE_STANDARD: return "standard";
    778             case ACTIVITY_TYPE_HOME: return "home";
    779             case ACTIVITY_TYPE_RECENTS: return "recents";
    780             case ACTIVITY_TYPE_ASSISTANT: return "assistant";
    781         }
    782         return String.valueOf(applicationType);
    783     }
    784 
    785     /** @hide */
    786     public static String alwaysOnTopToString(@AlwaysOnTop int alwaysOnTop) {
    787         switch (alwaysOnTop) {
    788             case ALWAYS_ON_TOP_UNDEFINED: return "undefined";
    789             case ALWAYS_ON_TOP_ON: return "on";
    790             case ALWAYS_ON_TOP_OFF: return "off";
    791         }
    792         return String.valueOf(alwaysOnTop);
    793     }
    794 }
    795