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 com.android.wm.shell.util;
18 
19 import android.annotation.IntDef;
20 import android.app.ActivityManager;
21 import android.app.WindowConfiguration;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.Nullable;
27 
28 import java.util.Arrays;
29 import java.util.List;
30 
31 /**
32  * Simple container for recent tasks.  May contain either a single or pair of tasks.
33  */
34 public class GroupedRecentTaskInfo implements Parcelable {
35 
36     public static final int TYPE_SINGLE = 1;
37     public static final int TYPE_SPLIT = 2;
38     public static final int TYPE_FREEFORM = 3;
39 
40     @IntDef(prefix = {"TYPE_"}, value = {
41             TYPE_SINGLE,
42             TYPE_SPLIT,
43             TYPE_FREEFORM
44     })
45     public @interface GroupType {}
46 
47     @NonNull
48     private final ActivityManager.RecentTaskInfo[] mTasks;
49     @Nullable
50     private final SplitBounds mSplitBounds;
51     @GroupType
52     private final int mType;
53 
54     /**
55      * Create new for a single task
56      */
forSingleTask( @onNull ActivityManager.RecentTaskInfo task)57     public static GroupedRecentTaskInfo forSingleTask(
58             @NonNull ActivityManager.RecentTaskInfo task) {
59         return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task}, null,
60                 TYPE_SINGLE);
61     }
62 
63     /**
64      * Create new for a pair of tasks in split screen
65      */
forSplitTasks(@onNull ActivityManager.RecentTaskInfo task1, @NonNull ActivityManager.RecentTaskInfo task2, @Nullable SplitBounds splitBounds)66     public static GroupedRecentTaskInfo forSplitTasks(@NonNull ActivityManager.RecentTaskInfo task1,
67             @NonNull ActivityManager.RecentTaskInfo task2, @Nullable SplitBounds splitBounds) {
68         return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task1, task2},
69                 splitBounds, TYPE_SPLIT);
70     }
71 
72     /**
73      * Create new for a group of freeform tasks
74      */
forFreeformTasks( @onNull ActivityManager.RecentTaskInfo... tasks)75     public static GroupedRecentTaskInfo forFreeformTasks(
76             @NonNull ActivityManager.RecentTaskInfo... tasks) {
77         return new GroupedRecentTaskInfo(tasks, null, TYPE_FREEFORM);
78     }
79 
GroupedRecentTaskInfo(@onNull ActivityManager.RecentTaskInfo[] tasks, @Nullable SplitBounds splitBounds, @GroupType int type)80     private GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo[] tasks,
81             @Nullable SplitBounds splitBounds, @GroupType int type) {
82         mTasks = tasks;
83         mSplitBounds = splitBounds;
84         mType = type;
85     }
86 
GroupedRecentTaskInfo(Parcel parcel)87     GroupedRecentTaskInfo(Parcel parcel) {
88         mTasks = parcel.createTypedArray(ActivityManager.RecentTaskInfo.CREATOR);
89         mSplitBounds = parcel.readTypedObject(SplitBounds.CREATOR);
90         mType = parcel.readInt();
91     }
92 
93     /**
94      * Get primary {@link ActivityManager.RecentTaskInfo}
95      */
96     @NonNull
getTaskInfo1()97     public ActivityManager.RecentTaskInfo getTaskInfo1() {
98         return mTasks[0];
99     }
100 
101     /**
102      * Get secondary {@link ActivityManager.RecentTaskInfo}.
103      *
104      * Used in split screen.
105      */
106     @Nullable
getTaskInfo2()107     public ActivityManager.RecentTaskInfo getTaskInfo2() {
108         if (mTasks.length > 1) {
109             return mTasks[1];
110         }
111         return null;
112     }
113 
114     /**
115      * Get all {@link ActivityManager.RecentTaskInfo}s grouped together.
116      */
117     @NonNull
getTaskInfoList()118     public List<ActivityManager.RecentTaskInfo> getTaskInfoList() {
119         return Arrays.asList(mTasks);
120     }
121 
122     /**
123      * Return {@link SplitBounds} if this is a split screen entry or {@code null}
124      */
125     @Nullable
getSplitBounds()126     public SplitBounds getSplitBounds() {
127         return mSplitBounds;
128     }
129 
130     /**
131      * Get type of this recents entry. One of {@link GroupType}
132      */
133     @GroupType
getType()134     public int getType() {
135         return mType;
136     }
137 
138     @Override
toString()139     public String toString() {
140         StringBuilder taskString = new StringBuilder();
141         for (int i = 0; i < mTasks.length; i++) {
142             if (i == 0) {
143                 taskString.append("Task");
144             } else {
145                 taskString.append(", Task");
146             }
147             taskString.append(i + 1).append(": ").append(getTaskInfo(mTasks[i]));
148         }
149         if (mSplitBounds != null) {
150             taskString.append(", SplitBounds: ").append(mSplitBounds);
151         }
152         taskString.append(", Type=");
153         switch (mType) {
154             case TYPE_SINGLE:
155                 taskString.append("TYPE_SINGLE");
156                 break;
157             case TYPE_SPLIT:
158                 taskString.append("TYPE_SPLIT");
159                 break;
160             case TYPE_FREEFORM:
161                 taskString.append("TYPE_FREEFORM");
162                 break;
163         }
164         return taskString.toString();
165     }
166 
getTaskInfo(ActivityManager.RecentTaskInfo taskInfo)167     private String getTaskInfo(ActivityManager.RecentTaskInfo taskInfo) {
168         if (taskInfo == null) {
169             return null;
170         }
171         return "id=" + taskInfo.taskId
172                 + " baseIntent=" + (taskInfo.baseIntent != null
173                         ? taskInfo.baseIntent.getComponent()
174                         : "null")
175                 + " winMode=" + WindowConfiguration.windowingModeToString(
176                         taskInfo.getWindowingMode());
177     }
178 
179     @Override
writeToParcel(Parcel parcel, int flags)180     public void writeToParcel(Parcel parcel, int flags) {
181         parcel.writeTypedArray(mTasks, flags);
182         parcel.writeTypedObject(mSplitBounds, flags);
183         parcel.writeInt(mType);
184     }
185 
186     @Override
describeContents()187     public int describeContents() {
188         return 0;
189     }
190 
191     public static final @android.annotation.NonNull Creator<GroupedRecentTaskInfo> CREATOR =
192             new Creator<GroupedRecentTaskInfo>() {
193         public GroupedRecentTaskInfo createFromParcel(Parcel source) {
194             return new GroupedRecentTaskInfo(source);
195         }
196         public GroupedRecentTaskInfo[] newArray(int size) {
197             return new GroupedRecentTaskInfo[size];
198         }
199     };
200 }