1 /*
2  * Copyright (C) 2018 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.ActivityTaskManager.INVALID_TASK_ID;
20 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.TestApi;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.content.ComponentName;
27 import android.content.Intent;
28 import android.content.LocusId;
29 import android.content.pm.ActivityInfo;
30 import android.content.res.Configuration;
31 import android.graphics.Point;
32 import android.graphics.Rect;
33 import android.os.Build;
34 import android.os.IBinder;
35 import android.os.Parcel;
36 import android.os.RemoteException;
37 import android.util.Log;
38 import android.view.DisplayCutout;
39 import android.window.TaskSnapshot;
40 import android.window.WindowContainerToken;
41 
42 import java.util.ArrayList;
43 import java.util.Objects;
44 
45 /**
46  * Stores information about a particular Task.
47  */
48 public class TaskInfo {
49     private static final String TAG = "TaskInfo";
50 
51     /**
52      * The id of the user the task was running as if this is a leaf task. The id of the current
53      * running user of the system otherwise.
54      * @hide
55      */
56     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
57     public int userId;
58 
59     /**
60      * The identifier for this task.
61      */
62     public int taskId;
63 
64     /**
65      * Whether or not this task has any running activities.
66      */
67     public boolean isRunning;
68 
69     /**
70      * The base intent of the task (generally the intent that launched the task). This intent can
71      * be used to relaunch the task (if it is no longer running) or brought to the front if it is.
72      */
73     @NonNull
74     public Intent baseIntent;
75 
76     /**
77      * The component of the first activity in the task, can be considered the "application" of this
78      * task.
79      */
80     @Nullable
81     public ComponentName baseActivity;
82 
83     /**
84      * The component of the top activity in the task, currently showing to the user.
85      */
86     @Nullable
87     public ComponentName topActivity;
88 
89     /**
90      * The component of the target activity if this task was started from an activity alias.
91      * Otherwise, this is null.
92      */
93     @Nullable
94     public ComponentName origActivity;
95 
96     /**
97      * The component of the activity that started this task (may be the component of the activity
98      * alias).
99      * @hide
100      */
101     @Nullable
102     public ComponentName realActivity;
103 
104     /**
105      * The number of activities in this task (including running).
106      */
107     public int numActivities;
108 
109     /**
110      * The last time this task was active since boot (including time spent in sleep).
111      * @hide
112      */
113     @UnsupportedAppUsage
114     public long lastActiveTime;
115 
116     /**
117      * The id of the display this task is associated with.
118      * @hide
119      */
120     public int displayId;
121 
122     /**
123      * The feature id of {@link com.android.server.wm.TaskDisplayArea} this task is associated with.
124      * @hide
125      */
126     public int displayAreaFeatureId = FEATURE_UNDEFINED;
127 
128     /**
129      * The recent activity values for the highest activity in the stack to have set the values.
130      * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.
131      */
132     @Nullable
133     public ActivityManager.TaskDescription taskDescription;
134 
135     /**
136      * The locusId of the task.
137      * @hide
138      */
139     @Nullable
140     public LocusId mTopActivityLocusId;
141 
142     /**
143      * True if the task can go in the split-screen primary stack.
144      * @hide
145      */
146     @UnsupportedAppUsage
147     public boolean supportsSplitScreenMultiWindow;
148 
149     /**
150      * Whether this task supports multi windowing modes based on the device settings and the
151      * root activity resizability and configuration.
152      * @hide
153      */
154     public boolean supportsMultiWindow;
155 
156     /**
157      * The resize mode of the task. See {@link ActivityInfo#resizeMode}.
158      * @hide
159      */
160     @UnsupportedAppUsage
161     public int resizeMode;
162 
163     /**
164      * The current configuration of the task.
165      * @hide
166      */
167     @NonNull
168     @UnsupportedAppUsage
169     public final Configuration configuration = new Configuration();
170 
171     /**
172      * Used as an opaque identifier for this task.
173      * @hide
174      */
175     @NonNull
176     public WindowContainerToken token;
177 
178     /**
179      * The PictureInPictureParams for the Task, if set.
180      * @hide
181      */
182     @Nullable
183     public PictureInPictureParams pictureInPictureParams;
184 
185     /**
186      * The {@link Rect} copied from {@link DisplayCutout#getSafeInsets()} if the cutout is not of
187      * (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS),
188      * {@code null} otherwise.
189      * @hide
190      */
191     @Nullable
192     public Rect displayCutoutInsets;
193 
194     /**
195      * The activity type of the top activity in this task.
196      * @hide
197      */
198     public @WindowConfiguration.ActivityType int topActivityType;
199 
200     /**
201      * The {@link ActivityInfo} of the top activity in this task.
202      * @hide
203      */
204     @Nullable
205     public ActivityInfo topActivityInfo;
206 
207     /**
208      * Whether the direct top activity is in size compat mode on foreground.
209      * @hide
210      */
211     public boolean topActivityInSizeCompat;
212 
213     /**
214      * Whether this task is resizable. Unlike {@link #resizeMode} (which is what the top activity
215      * supports), this is what the system actually uses for resizability based on other policy and
216      * developer options.
217      * @hide
218      */
219     public boolean isResizeable;
220 
221     /**
222      * Relative position of the task's top left corner in the parent container.
223      * @hide
224      */
225     public Point positionInParent;
226 
227     /**
228      * The launch cookies associated with activities in this task if any.
229      * @see ActivityOptions#setLaunchCookie(IBinder)
230      * @hide
231      */
232     public ArrayList<IBinder> launchCookies = new ArrayList<>();
233 
234     /**
235      * The identifier of the parent task that is created by organizer, otherwise
236      * {@link ActivityTaskManager#INVALID_TASK_ID}.
237      * @hide
238      */
239     public int parentTaskId;
240 
241     /**
242      * Whether this task is focused.
243      * @hide
244      */
245     public boolean isFocused;
246 
247     /**
248      * Whether this task is visible.
249      * @hide
250      */
251     public boolean isVisible;
252 
253     /**
254      * Whether this task is sleeping due to sleeping display.
255      * @hide
256      */
257     public boolean isSleeping;
258 
TaskInfo()259     TaskInfo() {
260         // Do nothing
261     }
262 
TaskInfo(Parcel source)263     private TaskInfo(Parcel source) {
264         readFromParcel(source);
265     }
266 
267     /**
268      * Whether this task is visible.
269      */
isVisible()270     public boolean isVisible() {
271         return isVisible;
272     }
273 
274     /**
275      * @param isLowResolution
276      * @return
277      * @hide
278      */
getTaskSnapshot(boolean isLowResolution)279     public TaskSnapshot getTaskSnapshot(boolean isLowResolution) {
280         try {
281             return ActivityTaskManager.getService().getTaskSnapshot(taskId, isLowResolution);
282         } catch (RemoteException e) {
283             Log.e(TAG, "Failed to get task snapshot, taskId=" + taskId, e);
284             return null;
285         }
286     }
287 
288     /** @hide */
289     @NonNull
290     @TestApi
getToken()291     public WindowContainerToken getToken() {
292         return token;
293     }
294 
295     /** @hide */
296     @NonNull
297     @TestApi
getConfiguration()298     public Configuration getConfiguration() {
299         return configuration;
300     }
301 
302     /** @hide */
303     @Nullable
304     @TestApi
getPictureInPictureParams()305     public PictureInPictureParams getPictureInPictureParams() {
306         return pictureInPictureParams;
307     }
308 
309     /** @hide */
310     @WindowConfiguration.WindowingMode
getWindowingMode()311     public int getWindowingMode() {
312         return configuration.windowConfiguration.getWindowingMode();
313     }
314 
315     /** @hide */
316     @WindowConfiguration.ActivityType
getActivityType()317     public int getActivityType() {
318         return configuration.windowConfiguration.getActivityType();
319     }
320 
321     /** @hide */
addLaunchCookie(IBinder cookie)322     public void addLaunchCookie(IBinder cookie) {
323         if (cookie == null || launchCookies.contains(cookie)) return;
324         launchCookies.add(cookie);
325     }
326 
327     /**
328      * @return {@code true} if this task contains the launch cookie.
329      * @hide
330      */
331     @TestApi
containsLaunchCookie(@onNull IBinder cookie)332     public boolean containsLaunchCookie(@NonNull IBinder cookie) {
333         return launchCookies.contains(cookie);
334     }
335 
336     /**
337      * @return The parent task id of this task.
338      * @hide
339      */
340     @TestApi
getParentTaskId()341     public int getParentTaskId() {
342         return parentTaskId;
343     }
344 
345     /** @hide */
346     @TestApi
hasParentTask()347     public boolean hasParentTask() {
348         return parentTaskId != INVALID_TASK_ID;
349     }
350 
351     /**
352      * Returns {@code true} if the parameters that are important for task organizers are equal
353      * between this {@link TaskInfo} and {@param that}.
354      * @hide
355      */
equalsForTaskOrganizer(@ullable TaskInfo that)356     public boolean equalsForTaskOrganizer(@Nullable TaskInfo that) {
357         if (that == null) {
358             return false;
359         }
360         return topActivityType == that.topActivityType
361                 && isResizeable == that.isResizeable
362                 && supportsMultiWindow == that.supportsMultiWindow
363                 && displayAreaFeatureId == that.displayAreaFeatureId
364                 && Objects.equals(positionInParent, that.positionInParent)
365                 && Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
366                 && Objects.equals(displayCutoutInsets, that.displayCutoutInsets)
367                 && getWindowingMode() == that.getWindowingMode()
368                 && Objects.equals(taskDescription, that.taskDescription)
369                 && isFocused == that.isFocused
370                 && isVisible == that.isVisible
371                 && isSleeping == that.isSleeping
372                 && Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId);
373     }
374 
375     /**
376      * @return {@code true} if parameters that are important for size compat have changed.
377      * @hide
378      */
equalsForSizeCompat(@ullable TaskInfo that)379     public boolean equalsForSizeCompat(@Nullable TaskInfo that) {
380         if (that == null) {
381             return false;
382         }
383         return displayId == that.displayId
384                 && taskId == that.taskId
385                 && topActivityInSizeCompat == that.topActivityInSizeCompat
386                 // Bounds are important if top activity is in size compat
387                 && (!topActivityInSizeCompat || configuration.windowConfiguration.getBounds()
388                     .equals(that.configuration.windowConfiguration.getBounds()))
389                 && (!topActivityInSizeCompat || configuration.getLayoutDirection()
390                     == that.configuration.getLayoutDirection())
391                 && (!topActivityInSizeCompat || isVisible == that.isVisible);
392     }
393 
394     /**
395      * Reads the TaskInfo from a parcel.
396      */
readFromParcel(Parcel source)397     void readFromParcel(Parcel source) {
398         userId = source.readInt();
399         taskId = source.readInt();
400         displayId = source.readInt();
401         isRunning = source.readBoolean();
402         baseIntent = source.readTypedObject(Intent.CREATOR);
403         baseActivity = ComponentName.readFromParcel(source);
404         topActivity = ComponentName.readFromParcel(source);
405         origActivity = ComponentName.readFromParcel(source);
406         realActivity = ComponentName.readFromParcel(source);
407 
408         numActivities = source.readInt();
409         lastActiveTime = source.readLong();
410 
411         taskDescription = source.readTypedObject(ActivityManager.TaskDescription.CREATOR);
412         supportsSplitScreenMultiWindow = source.readBoolean();
413         supportsMultiWindow = source.readBoolean();
414         resizeMode = source.readInt();
415         configuration.readFromParcel(source);
416         token = WindowContainerToken.CREATOR.createFromParcel(source);
417         topActivityType = source.readInt();
418         pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
419         displayCutoutInsets = source.readTypedObject(Rect.CREATOR);
420         topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
421         isResizeable = source.readBoolean();
422         source.readBinderList(launchCookies);
423         positionInParent = source.readTypedObject(Point.CREATOR);
424         parentTaskId = source.readInt();
425         isFocused = source.readBoolean();
426         isVisible = source.readBoolean();
427         isSleeping = source.readBoolean();
428         topActivityInSizeCompat = source.readBoolean();
429         mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR);
430         displayAreaFeatureId = source.readInt();
431     }
432 
433     /**
434      * Writes the TaskInfo to a parcel.
435      */
writeToParcel(Parcel dest, int flags)436     void writeToParcel(Parcel dest, int flags) {
437         dest.writeInt(userId);
438         dest.writeInt(taskId);
439         dest.writeInt(displayId);
440         dest.writeBoolean(isRunning);
441         dest.writeTypedObject(baseIntent, 0);
442 
443         ComponentName.writeToParcel(baseActivity, dest);
444         ComponentName.writeToParcel(topActivity, dest);
445         ComponentName.writeToParcel(origActivity, dest);
446         ComponentName.writeToParcel(realActivity, dest);
447 
448         dest.writeInt(numActivities);
449         dest.writeLong(lastActiveTime);
450 
451         dest.writeTypedObject(taskDescription, flags);
452         dest.writeBoolean(supportsSplitScreenMultiWindow);
453         dest.writeBoolean(supportsMultiWindow);
454         dest.writeInt(resizeMode);
455         configuration.writeToParcel(dest, flags);
456         token.writeToParcel(dest, flags);
457         dest.writeInt(topActivityType);
458         dest.writeTypedObject(pictureInPictureParams, flags);
459         dest.writeTypedObject(displayCutoutInsets, flags);
460         dest.writeTypedObject(topActivityInfo, flags);
461         dest.writeBoolean(isResizeable);
462         dest.writeBinderList(launchCookies);
463         dest.writeTypedObject(positionInParent, flags);
464         dest.writeInt(parentTaskId);
465         dest.writeBoolean(isFocused);
466         dest.writeBoolean(isVisible);
467         dest.writeBoolean(isSleeping);
468         dest.writeBoolean(topActivityInSizeCompat);
469         dest.writeTypedObject(mTopActivityLocusId, flags);
470         dest.writeInt(displayAreaFeatureId);
471     }
472 
473     @Override
toString()474     public String toString() {
475         return "TaskInfo{userId=" + userId + " taskId=" + taskId
476                 + " displayId=" + displayId
477                 + " isRunning=" + isRunning
478                 + " baseIntent=" + baseIntent + " baseActivity=" + baseActivity
479                 + " topActivity=" + topActivity + " origActivity=" + origActivity
480                 + " realActivity=" + realActivity
481                 + " numActivities=" + numActivities
482                 + " lastActiveTime=" + lastActiveTime
483                 + " supportsSplitScreenMultiWindow=" + supportsSplitScreenMultiWindow
484                 + " supportsMultiWindow=" + supportsMultiWindow
485                 + " resizeMode=" + resizeMode
486                 + " isResizeable=" + isResizeable
487                 + " token=" + token
488                 + " topActivityType=" + topActivityType
489                 + " pictureInPictureParams=" + pictureInPictureParams
490                 + " displayCutoutSafeInsets=" + displayCutoutInsets
491                 + " topActivityInfo=" + topActivityInfo
492                 + " launchCookies=" + launchCookies
493                 + " positionInParent=" + positionInParent
494                 + " parentTaskId=" + parentTaskId
495                 + " isFocused=" + isFocused
496                 + " isVisible=" + isVisible
497                 + " isSleeping=" + isSleeping
498                 + " topActivityInSizeCompat=" + topActivityInSizeCompat
499                 + " locusId=" + mTopActivityLocusId
500                 + " displayAreaFeatureId=" + displayAreaFeatureId
501                 + "}";
502     }
503 }
504