• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.window;
18 
19 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
20 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.res.Configuration;
25 import android.os.Parcelable;
26 import android.util.SparseIntArray;
27 
28 import com.android.internal.util.DataClass;
29 
30 import java.util.Arrays;
31 
32 /**
33  * Contains size-configuration buckets used to prevent excessive configuration changes during
34  * resize.
35  *
36  * These configurations are collected from application's resources based on size-sensitive
37  * qualifiers. For example, layout-w800dp will be added to mHorizontalSizeConfigurations as 800
38  * and drawable-sw400dp will be added to both as 400.
39  *
40  * @hide
41  */
42 @DataClass(genAidl = true)
43 public final class SizeConfigurationBuckets implements Parcelable {
44 
45     /** Horizontal (screenWidthDp) buckets */
46     @Nullable
47     private final int[] mHorizontal;
48 
49     /** Vertical (screenHeightDp) buckets */
50     @Nullable
51     private final int[] mVertical;
52 
53     /** Smallest (smallestScreenWidthDp) buckets */
54     @Nullable
55     private final int[] mSmallest;
56 
SizeConfigurationBuckets(Configuration[] sizeConfigurations)57     public SizeConfigurationBuckets(Configuration[] sizeConfigurations) {
58         SparseIntArray horizontal = new SparseIntArray();
59         SparseIntArray vertical = new SparseIntArray();
60         SparseIntArray smallest = new SparseIntArray();
61         for (int i = sizeConfigurations.length - 1; i >= 0; i--) {
62             Configuration config = sizeConfigurations[i];
63             if (config.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
64                 vertical.put(config.screenHeightDp, 0);
65             }
66             if (config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
67                 horizontal.put(config.screenWidthDp, 0);
68             }
69             if (config.smallestScreenWidthDp != Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
70                 smallest.put(config.smallestScreenWidthDp, 0);
71             }
72         }
73         mHorizontal = horizontal.copyKeys();
74         mVertical = vertical.copyKeys();
75         mSmallest = smallest.copyKeys();
76     }
77 
78     /**
79      * Get the changes between two configurations but don't count changes in sizes if they don't
80      * cross boundaries that are  important to the app.
81      *
82      * This is a static helper to deal with null `buckets`. When no buckets have been specified,
83      * this actually filters out all 3 size-configs. This is legacy behavior.
84      */
filterDiff(int diff, Configuration oldConfig, Configuration newConfig, @Nullable SizeConfigurationBuckets buckets)85     public static int filterDiff(int diff, Configuration oldConfig, Configuration newConfig,
86             @Nullable SizeConfigurationBuckets buckets) {
87         if (buckets == null) {
88             return diff & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE);
89         }
90         if ((diff & CONFIG_SCREEN_SIZE) != 0) {
91             final boolean crosses = buckets.crossesHorizontalSizeThreshold(oldConfig.screenWidthDp,
92                     newConfig.screenWidthDp)
93                     || buckets.crossesVerticalSizeThreshold(oldConfig.screenHeightDp,
94                     newConfig.screenHeightDp);
95             if (!crosses) {
96                 diff &= ~CONFIG_SCREEN_SIZE;
97             }
98         }
99         if ((diff & CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
100             final int oldSmallest = oldConfig.smallestScreenWidthDp;
101             final int newSmallest = newConfig.smallestScreenWidthDp;
102             if (!buckets.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
103                 diff &= ~CONFIG_SMALLEST_SCREEN_SIZE;
104             }
105         }
106         return diff;
107     }
108 
crossesHorizontalSizeThreshold(int firstDp, int secondDp)109     private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
110         return crossesSizeThreshold(mHorizontal, firstDp, secondDp);
111     }
112 
crossesVerticalSizeThreshold(int firstDp, int secondDp)113     private boolean crossesVerticalSizeThreshold(int firstDp, int secondDp) {
114         return crossesSizeThreshold(mVertical, firstDp, secondDp);
115     }
116 
crossesSmallestSizeThreshold(int firstDp, int secondDp)117     private boolean crossesSmallestSizeThreshold(int firstDp, int secondDp) {
118         return crossesSizeThreshold(mSmallest, firstDp, secondDp);
119     }
120 
121     /**
122      * The purpose of this method is to decide whether the activity needs to be relaunched upon
123      * changing its size. In most cases the activities don't need to be relaunched, if the resize
124      * is small, all the activity content has to do is relayout itself within new bounds. There are
125      * cases however, where the activity's content would be completely changed in the new size and
126      * the full relaunch is required.
127      *
128      * The activity will report to us vertical and horizontal thresholds after which a relaunch is
129      * required. These thresholds are collected from the application resource qualifiers. For
130      * example, if application has layout-w600dp resource directory, then it needs a relaunch when
131      * we resize from width of 650dp to 550dp, as it crosses the 600dp threshold. However, if
132      * it resizes width from 620dp to 700dp, it won't be relaunched as it stays on the same side
133      * of the threshold.
134      */
crossesSizeThreshold(int[] thresholds, int firstDp, int secondDp)135     private static boolean crossesSizeThreshold(int[] thresholds, int firstDp,
136             int secondDp) {
137         if (thresholds == null) {
138             return false;
139         }
140         for (int i = thresholds.length - 1; i >= 0; i--) {
141             final int threshold = thresholds[i];
142             if ((firstDp < threshold && secondDp >= threshold)
143                     || (firstDp >= threshold && secondDp < threshold)) {
144                 return true;
145             }
146         }
147         return false;
148     }
149 
150     @Override
toString()151     public String toString() {
152         return Arrays.toString(mHorizontal) + " " + Arrays.toString(mVertical) + " "
153                 + Arrays.toString(mSmallest);
154     }
155 
156 
157 
158     // Code below generated by codegen v1.0.22.
159     //
160     // DO NOT MODIFY!
161     // CHECKSTYLE:OFF Generated code
162     //
163     // To regenerate run:
164     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/window/SizeConfigurationBuckets.java
165     //
166     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
167     //   Settings > Editor > Code Style > Formatter Control
168     //@formatter:off
169 
170 
171     /**
172      * Creates a new SizeConfigurationBuckets.
173      *
174      * @param horizontal
175      *   Horizontal (screenWidthDp) buckets
176      * @param vertical
177      *   Vertical (screenHeightDp) buckets
178      * @param smallest
179      *   Smallest (smallestScreenWidthDp) buckets
180      */
181     @DataClass.Generated.Member
SizeConfigurationBuckets( @ullable int[] horizontal, @Nullable int[] vertical, @Nullable int[] smallest)182     public SizeConfigurationBuckets(
183             @Nullable int[] horizontal,
184             @Nullable int[] vertical,
185             @Nullable int[] smallest) {
186         this.mHorizontal = horizontal;
187         this.mVertical = vertical;
188         this.mSmallest = smallest;
189 
190         // onConstructed(); // You can define this method to get a callback
191     }
192 
193     /**
194      * Horizontal (screenWidthDp) buckets
195      */
196     @DataClass.Generated.Member
getHorizontal()197     public @Nullable int[] getHorizontal() {
198         return mHorizontal;
199     }
200 
201     /**
202      * Vertical (screenHeightDp) buckets
203      */
204     @DataClass.Generated.Member
getVertical()205     public @Nullable int[] getVertical() {
206         return mVertical;
207     }
208 
209     /**
210      * Smallest (smallestScreenWidthDp) buckets
211      */
212     @DataClass.Generated.Member
getSmallest()213     public @Nullable int[] getSmallest() {
214         return mSmallest;
215     }
216 
217     @Override
218     @DataClass.Generated.Member
writeToParcel(@onNull android.os.Parcel dest, int flags)219     public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
220         // You can override field parcelling by defining methods like:
221         // void parcelFieldName(Parcel dest, int flags) { ... }
222 
223         byte flg = 0;
224         if (mHorizontal != null) flg |= 0x1;
225         if (mVertical != null) flg |= 0x2;
226         if (mSmallest != null) flg |= 0x4;
227         dest.writeByte(flg);
228         if (mHorizontal != null) dest.writeIntArray(mHorizontal);
229         if (mVertical != null) dest.writeIntArray(mVertical);
230         if (mSmallest != null) dest.writeIntArray(mSmallest);
231     }
232 
233     @Override
234     @DataClass.Generated.Member
describeContents()235     public int describeContents() { return 0; }
236 
237     /** @hide */
238     @SuppressWarnings({"unchecked", "RedundantCast"})
239     @DataClass.Generated.Member
SizeConfigurationBuckets(@onNull android.os.Parcel in)240     /* package-private */ SizeConfigurationBuckets(@NonNull android.os.Parcel in) {
241         // You can override field unparcelling by defining methods like:
242         // static FieldType unparcelFieldName(Parcel in) { ... }
243 
244         byte flg = in.readByte();
245         int[] horizontal = (flg & 0x1) == 0 ? null : in.createIntArray();
246         int[] vertical = (flg & 0x2) == 0 ? null : in.createIntArray();
247         int[] smallest = (flg & 0x4) == 0 ? null : in.createIntArray();
248 
249         this.mHorizontal = horizontal;
250         this.mVertical = vertical;
251         this.mSmallest = smallest;
252 
253         // onConstructed(); // You can define this method to get a callback
254     }
255 
256     @DataClass.Generated.Member
257     public static final @NonNull Parcelable.Creator<SizeConfigurationBuckets> CREATOR
258             = new Parcelable.Creator<SizeConfigurationBuckets>() {
259         @Override
260         public SizeConfigurationBuckets[] newArray(int size) {
261             return new SizeConfigurationBuckets[size];
262         }
263 
264         @Override
265         public SizeConfigurationBuckets createFromParcel(@NonNull android.os.Parcel in) {
266             return new SizeConfigurationBuckets(in);
267         }
268     };
269 
270     @DataClass.Generated(
271             time = 1615845864280L,
272             codegenVersion = "1.0.22",
273             sourceFile = "frameworks/base/core/java/android/window/SizeConfigurationBuckets.java",
274             inputSignatures = "private final @android.annotation.Nullable int[] mHorizontal\nprivate final @android.annotation.Nullable int[] mVertical\nprivate final @android.annotation.Nullable int[] mSmallest\npublic static  int filterDiff(int,android.content.res.Configuration,android.content.res.Configuration,android.window.SizeConfigurationBuckets)\nprivate  boolean crossesHorizontalSizeThreshold(int,int)\nprivate  boolean crossesVerticalSizeThreshold(int,int)\nprivate  boolean crossesSmallestSizeThreshold(int,int)\nprivate static  boolean crossesSizeThreshold(int[],int,int)\npublic @java.lang.Override java.lang.String toString()\nclass SizeConfigurationBuckets extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true)")
275     @Deprecated
__metadata()276     private void __metadata() {}
277 
278 
279     //@formatter:on
280     // End of generated code
281 
282 }
283