• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.TaskInfo.PROPERTY_VALUE_UNSET;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.graphics.Rect;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.util.Objects;
31 
32 /**
33  * Stores App Compat information about a particular Task.
34  * @hide
35  */
36 public class AppCompatTaskInfo implements Parcelable {
37     /**
38      * If {@link #isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position
39      * or {@link TaskInfo#PROPERTY_VALUE_UNSET} otherwise.
40      */
41     public int topActivityLetterboxVerticalPosition = PROPERTY_VALUE_UNSET;
42 
43     /**
44      * If {@link #isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position
45      * or {@link TaskInfo#PROPERTY_VALUE_UNSET} otherwise.
46      */
47     public int topActivityLetterboxHorizontalPosition = PROPERTY_VALUE_UNSET;
48 
49     /**
50      * If {@link #isLetterboxDoubleTapEnabled} it contains the current width of the letterboxed
51      * activity or {@link TaskInfo#PROPERTY_VALUE_UNSET} otherwise.
52      */
53     public int topActivityLetterboxWidth = PROPERTY_VALUE_UNSET;
54 
55     /**
56      * If {@link #isLetterboxDoubleTapEnabled} it contains the current height of the letterboxed
57      * activity or {@link TaskInfo#PROPERTY_VALUE_UNSET} otherwise.
58      */
59     public int topActivityLetterboxHeight = PROPERTY_VALUE_UNSET;
60 
61     /**
62      * Contains the app bounds of the top activity or size compat mode
63      * bounds when in size compat mode. If null, contains bounds.
64      */
65     @NonNull
66     public final Rect topActivityAppBounds = new Rect();
67 
68     /**
69      * Contains the top activity bounds when the activity is letterboxed.
70      * It's {@code null} if there's no top activity in the task or it's not letterboxed.
71      */
72     // TODO(b/379824541) Remove duplicate information.
73     @Nullable
74     public Rect topActivityLetterboxBounds;
75 
76     /**
77      * Stores camera-related app compat information about a particular Task.
78      */
79     public CameraCompatTaskInfo cameraCompatTaskInfo = CameraCompatTaskInfo.create();
80 
81     /** Constant indicating no top activity flag has been set. */
82     private static final int FLAG_UNDEFINED = 0x0;
83     /** Constant base value for top activity flag. */
84     private static final int FLAG_BASE = 0x1;
85     /** Top activity flag for whether letterbox education is enabled. */
86     private static final int FLAG_LETTERBOX_EDU_ENABLED = FLAG_BASE;
87     /** Top activity flag for whether activity is eligible for letterbox education. */
88     private static final int FLAG_ELIGIBLE_FOR_LETTERBOX_EDU = FLAG_BASE << 1;
89     /** Top activity flag for whether activity bounds are letterboxed. */
90     private static final int FLAG_LETTERBOXED = FLAG_BASE << 2;
91     /** Top activity flag for whether activity is in size compat mode. */
92     private static final int FLAG_IN_SIZE_COMPAT = FLAG_BASE << 3;
93     /** Top activity flag for whether letterbox double tap is enabled. */
94     private static final int FLAG_LETTERBOX_DOUBLE_TAP_ENABLED = FLAG_BASE << 4;
95     /** Top activity flag for whether the update comes from a letterbox double tap action. */
96     private static final int FLAG_IS_FROM_LETTERBOX_DOUBLE_TAP = FLAG_BASE << 5;
97     /** Top activity flag for whether activity is eligible for user aspect ratio button. */
98     private static final int FLAG_ELIGIBLE_FOR_USER_ASPECT_RATIO_BUTTON = FLAG_BASE << 6;
99     /** Top activity flag for whether has activity has been overridden to fullscreen by system. */
100     private static final int FLAG_FULLSCREEN_OVERRIDE_SYSTEM = FLAG_BASE << 7;
101     /** Top activity flag for whether has activity has been overridden to fullscreen by user. */
102     private static final int FLAG_FULLSCREEN_OVERRIDE_USER = FLAG_BASE << 8;
103     /** Top activity flag for whether min aspect ratio of the activity has been overridden.*/
104     public static final int FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE = FLAG_BASE << 9;
105     /** Top activity flag for whether restart menu is shown due to display move. */
106     private static final int FLAG_ENABLE_RESTART_MENU_FOR_DISPLAY_MOVE = FLAG_BASE << 10;
107     /** Top activity flag for whether activity opted out of edge to edge. */
108     public static final int FLAG_OPT_OUT_EDGE_TO_EDGE = FLAG_BASE << 11;
109 
110     @Retention(RetentionPolicy.SOURCE)
111     @IntDef(flag = true, value = {
112             FLAG_UNDEFINED,
113             FLAG_LETTERBOX_EDU_ENABLED,
114             FLAG_ELIGIBLE_FOR_LETTERBOX_EDU,
115             FLAG_LETTERBOXED,
116             FLAG_IN_SIZE_COMPAT,
117             FLAG_LETTERBOX_DOUBLE_TAP_ENABLED,
118             FLAG_IS_FROM_LETTERBOX_DOUBLE_TAP,
119             FLAG_ELIGIBLE_FOR_USER_ASPECT_RATIO_BUTTON,
120             FLAG_FULLSCREEN_OVERRIDE_SYSTEM,
121             FLAG_FULLSCREEN_OVERRIDE_USER,
122             FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE,
123             FLAG_ENABLE_RESTART_MENU_FOR_DISPLAY_MOVE,
124             FLAG_OPT_OUT_EDGE_TO_EDGE
125     })
126     public @interface TopActivityFlag {}
127 
128     /**
129      * A combination of {@link TopActivityFlag}s that have been enabled through
130      * {@link #setTopActivityFlag}.
131      */
132     @TopActivityFlag
133     private int mTopActivityFlags;
134 
135     @TopActivityFlag
136     private static final int FLAGS_ORGANIZER_INTERESTED = FLAG_IS_FROM_LETTERBOX_DOUBLE_TAP
137             | FLAG_ELIGIBLE_FOR_USER_ASPECT_RATIO_BUTTON | FLAG_FULLSCREEN_OVERRIDE_SYSTEM
138             | FLAG_FULLSCREEN_OVERRIDE_USER | FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE
139             | FLAG_OPT_OUT_EDGE_TO_EDGE | FLAG_ENABLE_RESTART_MENU_FOR_DISPLAY_MOVE;
140 
141     @TopActivityFlag
142     private static final int FLAGS_COMPAT_UI_INTERESTED = FLAGS_ORGANIZER_INTERESTED
143             | FLAG_IN_SIZE_COMPAT | FLAG_ELIGIBLE_FOR_LETTERBOX_EDU | FLAG_LETTERBOX_EDU_ENABLED
144             | FLAG_ENABLE_RESTART_MENU_FOR_DISPLAY_MOVE;
145 
AppCompatTaskInfo()146     private AppCompatTaskInfo() {
147         // Do nothing
148     }
149 
150     @NonNull
create()151     static AppCompatTaskInfo create() {
152         return new AppCompatTaskInfo();
153     }
154 
AppCompatTaskInfo(Parcel source)155     private AppCompatTaskInfo(Parcel source) {
156         readFromParcel(source);
157     }
158 
159     @Override
describeContents()160     public int describeContents() {
161         return 0;
162     }
163 
164     public static final Creator<AppCompatTaskInfo> CREATOR =
165             new Creator<>() {
166                 @Override
167                 public AppCompatTaskInfo createFromParcel(Parcel in) {
168                     return new AppCompatTaskInfo(in);
169                 }
170 
171                 @Override
172                 public AppCompatTaskInfo[] newArray(int size) {
173                     return new AppCompatTaskInfo[size];
174                 }
175             };
176 
177     /**
178      * @return {@code true} if the task has some compat ui.
179      */
hasCompatUI()180     public boolean hasCompatUI() {
181         return isTopActivityInSizeCompat() || eligibleForLetterboxEducation()
182                 || isLetterboxDoubleTapEnabled() || eligibleForUserAspectRatioButton()
183                 || isRestartMenuEnabledForDisplayMove();
184     }
185 
186     /**
187      * @return {@code true} if the top activity bounds are letterboxed with width <= height.
188      */
isTopActivityPillarboxShaped()189     public boolean isTopActivityPillarboxShaped() {
190         return isTopActivityLetterboxed()
191                 && topActivityLetterboxWidth <= topActivityLetterboxHeight;
192     }
193 
194     /**
195      * @return {@code true} if the letterbox education is enabled.
196      */
isLetterboxEducationEnabled()197     public boolean isLetterboxEducationEnabled() {
198         return isTopActivityFlagEnabled(FLAG_LETTERBOX_EDU_ENABLED);
199     }
200 
201     /**
202      * Sets the top activity flag for whether letterbox education is enabled.
203      */
setLetterboxEducationEnabled(boolean enable)204     public void setLetterboxEducationEnabled(boolean enable) {
205         setTopActivityFlag(FLAG_LETTERBOX_EDU_ENABLED, enable);
206     }
207 
208     /**
209      * @return {@code true} if the direct top activity is eligible for letterbox education.
210      */
eligibleForLetterboxEducation()211     public boolean eligibleForLetterboxEducation() {
212         return isTopActivityFlagEnabled(FLAG_ELIGIBLE_FOR_LETTERBOX_EDU);
213     }
214 
215     /**
216      * Sets the top activity flag to be eligible for letterbox education.
217      */
setEligibleForLetterboxEducation(boolean enable)218     public void setEligibleForLetterboxEducation(boolean enable) {
219         setTopActivityFlag(FLAG_ELIGIBLE_FOR_LETTERBOX_EDU, enable);
220     }
221 
222     /**
223      * @return {@code true} if the direct top activity is eligible for the user aspect ratio
224      * settings button.
225      */
eligibleForUserAspectRatioButton()226     public boolean eligibleForUserAspectRatioButton() {
227         return isTopActivityFlagEnabled(FLAG_ELIGIBLE_FOR_USER_ASPECT_RATIO_BUTTON);
228     }
229 
230     /**
231      * Sets the top activity flag to be eligible for the user aspect ratio settings button.
232      */
setEligibleForUserAspectRatioButton(boolean enable)233     public void setEligibleForUserAspectRatioButton(boolean enable) {
234         setTopActivityFlag(FLAG_ELIGIBLE_FOR_USER_ASPECT_RATIO_BUTTON, enable);
235     }
236 
237     /**
238      * @return {@code true} if double tap to reposition letterboxed app is enabled.
239      */
isLetterboxDoubleTapEnabled()240     public boolean isLetterboxDoubleTapEnabled() {
241         return isTopActivityFlagEnabled(FLAG_LETTERBOX_DOUBLE_TAP_ENABLED);
242     }
243 
244     /**
245      * Sets the top activity flag to enable double tap to reposition letterboxed app.
246      */
setLetterboxDoubleTapEnabled(boolean enable)247     public void setLetterboxDoubleTapEnabled(boolean enable) {
248         setTopActivityFlag(FLAG_LETTERBOX_DOUBLE_TAP_ENABLED, enable);
249     }
250 
251     /**
252      * @return {@code true} if the update comes from a letterbox double-tap action from the user.
253      */
isFromLetterboxDoubleTap()254     public boolean isFromLetterboxDoubleTap() {
255         return isTopActivityFlagEnabled(FLAG_IS_FROM_LETTERBOX_DOUBLE_TAP);
256     }
257 
258     /**
259      * Sets the top activity flag for whether the update comes from a letterbox double-tap action
260      * from the user.
261      */
setIsFromLetterboxDoubleTap(boolean enable)262     public void setIsFromLetterboxDoubleTap(boolean enable) {
263         setTopActivityFlag(FLAG_IS_FROM_LETTERBOX_DOUBLE_TAP, enable);
264     }
265 
266     /**
267      * @return {@code true} if the user has forced the activity to be fullscreen through the
268      * user aspect ratio settings.
269      */
isUserFullscreenOverrideEnabled()270     public boolean isUserFullscreenOverrideEnabled() {
271         return isTopActivityFlagEnabled(FLAG_FULLSCREEN_OVERRIDE_USER);
272     }
273 
274     /**
275      * Sets the top activity flag for whether the user has forced the activity to be fullscreen
276      * through the user aspect ratio settings.
277      */
setUserFullscreenOverrideEnabled(boolean enable)278     public void setUserFullscreenOverrideEnabled(boolean enable) {
279         setTopActivityFlag(FLAG_FULLSCREEN_OVERRIDE_USER, enable);
280     }
281 
282     /**
283      * @return {@code true} if the system has forced the activity to be fullscreen.
284      */
isSystemFullscreenOverrideEnabled()285     public boolean isSystemFullscreenOverrideEnabled() {
286         return isTopActivityFlagEnabled(FLAG_FULLSCREEN_OVERRIDE_SYSTEM);
287     }
288 
289     /**
290      * Sets the top activity flag for whether the system has forced the activity to be fullscreen.
291      */
setSystemFullscreenOverrideEnabled(boolean enable)292     public void setSystemFullscreenOverrideEnabled(boolean enable) {
293         setTopActivityFlag(FLAG_FULLSCREEN_OVERRIDE_SYSTEM, enable);
294     }
295 
296     /**
297      * @return {@code true} if the direct top activity is in size compat mode on foreground.
298      */
isTopActivityInSizeCompat()299     public boolean isTopActivityInSizeCompat() {
300         return isTopActivityFlagEnabled(FLAG_IN_SIZE_COMPAT);
301     }
302 
303     /**
304      * Sets the top activity flag for whether the direct top activity is in size compat mode
305      * on foreground.
306      */
setTopActivityInSizeCompat(boolean enable)307     public void setTopActivityInSizeCompat(boolean enable) {
308         setTopActivityFlag(FLAG_IN_SIZE_COMPAT, enable);
309     }
310 
311     /**
312      * @return {@code true} if the restart menu is enabled for the top activity due to display move.
313      */
isRestartMenuEnabledForDisplayMove()314     public boolean isRestartMenuEnabledForDisplayMove() {
315         return isTopActivityFlagEnabled(FLAG_ENABLE_RESTART_MENU_FOR_DISPLAY_MOVE);
316     }
317 
318     /**
319      * Sets the top activity flag for whether the restart menu is enabled for the top activity due
320      * to display move.
321      */
setRestartMenuEnabledForDisplayMove(boolean enable)322     public void setRestartMenuEnabledForDisplayMove(boolean enable) {
323         setTopActivityFlag(FLAG_ENABLE_RESTART_MENU_FOR_DISPLAY_MOVE, enable);
324     }
325 
326     /**
327      * @return {@code true} if the top activity bounds are letterboxed.
328      */
isTopActivityLetterboxed()329     public boolean isTopActivityLetterboxed() {
330         return isTopActivityFlagEnabled(FLAG_LETTERBOXED);
331     }
332 
333     /**
334      * Sets the top activity flag for whether the top activity bounds are letterboxed.
335      */
setTopActivityLetterboxed(boolean enable)336     public void setTopActivityLetterboxed(boolean enable) {
337         setTopActivityFlag(FLAG_LETTERBOXED, enable);
338     }
339 
340     /**
341      * @return {@code true} if the top activity's min aspect ratio has been overridden.
342      */
hasMinAspectRatioOverride()343     public boolean hasMinAspectRatioOverride() {
344         return isTopActivityFlagEnabled(FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE);
345     }
346 
347     /**
348      * Sets the top activity flag for whether the min aspect ratio of the activity has been
349      * overridden.
350      */
setHasMinAspectRatioOverride(boolean enable)351     public void setHasMinAspectRatioOverride(boolean enable) {
352         setTopActivityFlag(FLAG_HAS_MIN_ASPECT_RATIO_OVERRIDE, enable);
353     }
354 
355     /**
356      * Sets the top activity flag for whether the activity has opted out of edge to edge.
357      */
setOptOutEdgeToEdge(boolean enable)358     public void setOptOutEdgeToEdge(boolean enable) {
359         setTopActivityFlag(FLAG_OPT_OUT_EDGE_TO_EDGE, enable);
360     }
361 
362     /**
363      * @return {@code true} if the top activity has opted out of edge to edge.
364      */
hasOptOutEdgeToEdge()365     public boolean hasOptOutEdgeToEdge() {
366         return isTopActivityFlagEnabled(FLAG_OPT_OUT_EDGE_TO_EDGE);
367     }
368 
369     /** Clear all top activity flags and set to false. */
clearTopActivityFlags()370     public void clearTopActivityFlags() {
371         mTopActivityFlags = FLAG_UNDEFINED;
372     }
373 
374     /**
375      * @return {@code true} if the app compat parameters that are important for task organizers
376      * are equal.
377      */
equalsForTaskOrganizer(@ullable AppCompatTaskInfo that)378     public boolean equalsForTaskOrganizer(@Nullable AppCompatTaskInfo that) {
379         if (that == null) {
380             return false;
381         }
382         return (mTopActivityFlags & FLAGS_ORGANIZER_INTERESTED)
383                     == (that.mTopActivityFlags & FLAGS_ORGANIZER_INTERESTED)
384                 && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
385                 && topActivityLetterboxWidth == that.topActivityLetterboxWidth
386                 && topActivityLetterboxHeight == that.topActivityLetterboxHeight
387                 && topActivityAppBounds.equals(that.topActivityAppBounds)
388                 && topActivityLetterboxHorizontalPosition
389                     == that.topActivityLetterboxHorizontalPosition
390                 && cameraCompatTaskInfo.equalsForTaskOrganizer(that.cameraCompatTaskInfo);
391     }
392 
393     /**
394      * @return {@code true} if parameters that are important for size compat have changed.
395      */
equalsForCompatUi(@ullable AppCompatTaskInfo that)396     public boolean equalsForCompatUi(@Nullable AppCompatTaskInfo that) {
397         if (that == null) {
398             return false;
399         }
400         return (mTopActivityFlags & FLAGS_COMPAT_UI_INTERESTED)
401                     == (that.mTopActivityFlags & FLAGS_COMPAT_UI_INTERESTED)
402                 && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
403                 && topActivityLetterboxHorizontalPosition
404                     == that.topActivityLetterboxHorizontalPosition
405                 && topActivityLetterboxWidth == that.topActivityLetterboxWidth
406                 && topActivityLetterboxHeight == that.topActivityLetterboxHeight
407                 && topActivityAppBounds.equals(that.topActivityAppBounds)
408                 && cameraCompatTaskInfo.equalsForCompatUi(that.cameraCompatTaskInfo);
409     }
410 
411     /**
412      * Reads the AppCompatTaskInfo from a parcel.
413      */
readFromParcel(Parcel source)414     void readFromParcel(Parcel source) {
415         mTopActivityFlags = source.readInt();
416         topActivityLetterboxVerticalPosition = source.readInt();
417         topActivityLetterboxHorizontalPosition = source.readInt();
418         topActivityLetterboxWidth = source.readInt();
419         topActivityLetterboxHeight = source.readInt();
420         topActivityAppBounds.set(Objects.requireNonNull(source.readTypedObject(Rect.CREATOR)));
421         topActivityLetterboxBounds = source.readTypedObject(Rect.CREATOR);
422         cameraCompatTaskInfo = source.readTypedObject(CameraCompatTaskInfo.CREATOR);
423     }
424 
425     /**
426      * Writes the AppCompatTaskInfo to a parcel.
427      */
428     @Override
writeToParcel(Parcel dest, int flags)429     public void writeToParcel(Parcel dest, int flags) {
430         dest.writeInt(mTopActivityFlags);
431         dest.writeInt(topActivityLetterboxVerticalPosition);
432         dest.writeInt(topActivityLetterboxHorizontalPosition);
433         dest.writeInt(topActivityLetterboxWidth);
434         dest.writeInt(topActivityLetterboxHeight);
435         dest.writeTypedObject(topActivityAppBounds, flags);
436         dest.writeTypedObject(topActivityLetterboxBounds, flags);
437         dest.writeTypedObject(cameraCompatTaskInfo, flags);
438     }
439 
440     @Override
toString()441     public String toString() {
442         return "AppCompatTaskInfo { topActivityInSizeCompat=" + isTopActivityInSizeCompat()
443                 + " eligibleForLetterboxEducation= " + eligibleForLetterboxEducation()
444                 + " isLetterboxEducationEnabled= " + isLetterboxEducationEnabled()
445                 + " isLetterboxDoubleTapEnabled= " + isLetterboxDoubleTapEnabled()
446                 + " eligibleForUserAspectRatioButton= " + eligibleForUserAspectRatioButton()
447                 + " topActivityBoundsLetterboxed= " + isTopActivityLetterboxed()
448                 + " isFromLetterboxDoubleTap= " + isFromLetterboxDoubleTap()
449                 + " topActivityLetterboxVerticalPosition= " + topActivityLetterboxVerticalPosition
450                 + " topActivityLetterboxHorizontalPosition= "
451                 + topActivityLetterboxHorizontalPosition
452                 + " topActivityLetterboxWidth=" + topActivityLetterboxWidth
453                 + " topActivityLetterboxHeight=" + topActivityLetterboxHeight
454                 + " topActivityAppBounds=" + topActivityAppBounds
455                 + " isUserFullscreenOverrideEnabled=" + isUserFullscreenOverrideEnabled()
456                 + " isSystemFullscreenOverrideEnabled=" + isSystemFullscreenOverrideEnabled()
457                 + " hasMinAspectRatioOverride=" + hasMinAspectRatioOverride()
458                 + " topActivityLetterboxBounds=" + topActivityLetterboxBounds
459                 + " cameraCompatTaskInfo=" + cameraCompatTaskInfo.toString()
460                 + "}";
461     }
462 
setTopActivityFlag(@opActivityFlag int flag, boolean enable)463     private void setTopActivityFlag(@TopActivityFlag int flag, boolean enable) {
464         mTopActivityFlags = enable ? (mTopActivityFlags | flag) : (mTopActivityFlags & ~flag);
465     }
466 
isTopActivityFlagEnabled(@opActivityFlag int flag)467     private boolean isTopActivityFlagEnabled(@TopActivityFlag int flag) {
468         return (mTopActivityFlags & flag) == flag;
469     }
470 }
471