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.app.WindowConfiguration.WindowingMode; 20 21 import static java.util.Objects.requireNonNull; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.TestApi; 26 import android.content.res.Configuration; 27 import android.graphics.Point; 28 import android.graphics.Rect; 29 import android.os.IBinder; 30 import android.os.Parcel; 31 import android.os.Parcelable; 32 33 import java.util.ArrayList; 34 import java.util.List; 35 36 /** 37 * Stores information about a particular TaskFragment. 38 * @hide 39 */ 40 @TestApi 41 public final class TaskFragmentInfo implements Parcelable { 42 43 /** 44 * Client assigned unique token in {@link TaskFragmentCreationParams#getFragmentToken()} to 45 * create this TaskFragment with. 46 */ 47 @NonNull 48 private final IBinder mFragmentToken; 49 50 @NonNull 51 private final WindowContainerToken mToken; 52 53 @NonNull 54 private final Configuration mConfiguration = new Configuration(); 55 56 /** The number of the running activities in the TaskFragment. */ 57 private final int mRunningActivityCount; 58 59 /** Whether this TaskFragment is visible on the window hierarchy. */ 60 private final boolean mIsVisible; 61 62 /** 63 * List of Activity tokens that are children of this TaskFragment. It only contains Activities 64 * that belong to the organizer process for security. 65 */ 66 @NonNull 67 private final List<IBinder> mActivities = new ArrayList<>(); 68 69 /** 70 * List of Activity tokens that were explicitly requested to be launched in this TaskFragment. 71 * It only contains Activities that belong to the organizer process for security. 72 */ 73 @NonNull 74 private final List<IBinder> mInRequestedTaskFragmentActivities = new ArrayList<>(); 75 76 /** Relative position of the fragment's top left corner in the parent container. */ 77 private final Point mPositionInParent = new Point(); 78 79 /** 80 * Whether the last running activity in the TaskFragment was finished due to clearing task while 81 * launching an activity in the host Task. 82 */ 83 private final boolean mIsTaskClearedForReuse; 84 85 /** 86 * Whether the last running activity in the TaskFragment was reparented to a different Task 87 * because it is entering PiP. 88 */ 89 private final boolean mIsTaskFragmentClearedForPip; 90 91 /** 92 * Whether the last running activity of the TaskFragment was removed because it was reordered to 93 * front of the Task. 94 */ 95 private final boolean mIsClearedForReorderActivityToFront; 96 97 /** 98 * The maximum {@link android.content.pm.ActivityInfo.WindowLayout#minWidth} and 99 * {@link android.content.pm.ActivityInfo.WindowLayout#minHeight} aggregated from the 100 * TaskFragment's child activities. 101 */ 102 @NonNull 103 private final Point mMinimumDimensions = new Point(); 104 105 private final boolean mIsTopNonFishingChild; 106 107 /** @hide */ TaskFragmentInfo( @onNull IBinder fragmentToken, @NonNull WindowContainerToken token, @NonNull Configuration configuration, int runningActivityCount, boolean isVisible, @NonNull List<IBinder> activities, @NonNull List<IBinder> inRequestedTaskFragmentActivities, @NonNull Point positionInParent, boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip, boolean isClearedForReorderActivityToFront, @NonNull Point minimumDimensions, boolean isTopNonFinishingChild)108 public TaskFragmentInfo( 109 @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token, 110 @NonNull Configuration configuration, int runningActivityCount, 111 boolean isVisible, @NonNull List<IBinder> activities, 112 @NonNull List<IBinder> inRequestedTaskFragmentActivities, 113 @NonNull Point positionInParent, boolean isTaskClearedForReuse, 114 boolean isTaskFragmentClearedForPip, boolean isClearedForReorderActivityToFront, 115 @NonNull Point minimumDimensions, boolean isTopNonFinishingChild) { 116 mFragmentToken = requireNonNull(fragmentToken); 117 mToken = requireNonNull(token); 118 mConfiguration.setTo(configuration); 119 mRunningActivityCount = runningActivityCount; 120 mIsVisible = isVisible; 121 mActivities.addAll(activities); 122 mInRequestedTaskFragmentActivities.addAll(inRequestedTaskFragmentActivities); 123 mPositionInParent.set(positionInParent); 124 mIsTaskClearedForReuse = isTaskClearedForReuse; 125 mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip; 126 mIsClearedForReorderActivityToFront = isClearedForReorderActivityToFront; 127 mMinimumDimensions.set(minimumDimensions); 128 mIsTopNonFishingChild = isTopNonFinishingChild; 129 } 130 131 @NonNull getFragmentToken()132 public IBinder getFragmentToken() { 133 return mFragmentToken; 134 } 135 136 @NonNull getToken()137 public WindowContainerToken getToken() { 138 return mToken; 139 } 140 141 @NonNull getConfiguration()142 public Configuration getConfiguration() { 143 return mConfiguration; 144 } 145 isEmpty()146 public boolean isEmpty() { 147 return mRunningActivityCount == 0; 148 } 149 hasRunningActivity()150 public boolean hasRunningActivity() { 151 return mRunningActivityCount > 0; 152 } 153 getRunningActivityCount()154 public int getRunningActivityCount() { 155 return mRunningActivityCount; 156 } 157 isVisible()158 public boolean isVisible() { 159 return mIsVisible; 160 } 161 162 @NonNull getActivities()163 public List<IBinder> getActivities() { 164 return mActivities; 165 } 166 167 @NonNull getActivitiesRequestedInTaskFragment()168 public List<IBinder> getActivitiesRequestedInTaskFragment() { 169 return mInRequestedTaskFragmentActivities; 170 } 171 172 /** Returns the relative position of the fragment's top left corner in the parent container. */ 173 @NonNull getPositionInParent()174 public Point getPositionInParent() { 175 return mPositionInParent; 176 } 177 isTaskClearedForReuse()178 public boolean isTaskClearedForReuse() { 179 return mIsTaskClearedForReuse; 180 } 181 182 /** @hide */ isTaskFragmentClearedForPip()183 public boolean isTaskFragmentClearedForPip() { 184 return mIsTaskFragmentClearedForPip; 185 } 186 187 /** @hide */ isClearedForReorderActivityToFront()188 public boolean isClearedForReorderActivityToFront() { 189 return mIsClearedForReorderActivityToFront; 190 } 191 192 @WindowingMode getWindowingMode()193 public int getWindowingMode() { 194 return mConfiguration.windowConfiguration.getWindowingMode(); 195 } 196 197 /** 198 * Returns the minimum width this TaskFragment can be resized to. 199 * Client side must not {@link WindowContainerTransaction#setRelativeBounds} 200 * that {@link Rect#width()} is shorter than the reported value. 201 * @hide pending unhide 202 */ getMinimumWidth()203 public int getMinimumWidth() { 204 return mMinimumDimensions.x; 205 } 206 207 /** 208 * Returns the minimum width this TaskFragment can be resized to. 209 * Client side must not {@link WindowContainerTransaction#setRelativeBounds} 210 * that {@link Rect#height()} is shorter than the reported value. 211 * @hide pending unhide 212 */ getMinimumHeight()213 public int getMinimumHeight() { 214 return mMinimumDimensions.y; 215 } 216 217 /** 218 * Indicates that this TaskFragment is the top non-finishing child of its parent container 219 * among all Activities and TaskFragment siblings. 220 * 221 * @hide 222 */ isTopNonFinishingChild()223 public boolean isTopNonFinishingChild() { 224 return mIsTopNonFishingChild; 225 } 226 227 /** 228 * Returns {@code true} if the parameters that are important for task fragment organizers are 229 * equal between this {@link TaskFragmentInfo} and {@param that}. 230 * Note that this method is usually called with 231 * {@link com.android.server.wm.WindowOrganizerController#configurationsAreEqualForOrganizer( 232 * Configuration, Configuration)} to determine if this {@link TaskFragmentInfo} should 233 * be dispatched to the client. 234 */ equalsForTaskFragmentOrganizer(@ullable TaskFragmentInfo that)235 public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentInfo that) { 236 if (that == null) { 237 return false; 238 } 239 240 return mFragmentToken.equals(that.mFragmentToken) 241 && mToken.equals(that.mToken) 242 && mRunningActivityCount == that.mRunningActivityCount 243 && mIsVisible == that.mIsVisible 244 && getWindowingMode() == that.getWindowingMode() 245 && mActivities.equals(that.mActivities) 246 && mInRequestedTaskFragmentActivities.equals( 247 that.mInRequestedTaskFragmentActivities) 248 && mPositionInParent.equals(that.mPositionInParent) 249 && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse 250 && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip 251 && mIsClearedForReorderActivityToFront == that.mIsClearedForReorderActivityToFront 252 && mMinimumDimensions.equals(that.mMinimumDimensions) 253 && mIsTopNonFishingChild == that.mIsTopNonFishingChild; 254 } 255 TaskFragmentInfo(Parcel in)256 private TaskFragmentInfo(Parcel in) { 257 mFragmentToken = in.readStrongBinder(); 258 mToken = in.readTypedObject(WindowContainerToken.CREATOR); 259 mConfiguration.readFromParcel(in); 260 mRunningActivityCount = in.readInt(); 261 mIsVisible = in.readBoolean(); 262 in.readBinderList(mActivities); 263 in.readBinderList(mInRequestedTaskFragmentActivities); 264 mPositionInParent.readFromParcel(in); 265 mIsTaskClearedForReuse = in.readBoolean(); 266 mIsTaskFragmentClearedForPip = in.readBoolean(); 267 mIsClearedForReorderActivityToFront = in.readBoolean(); 268 mMinimumDimensions.readFromParcel(in); 269 mIsTopNonFishingChild = in.readBoolean(); 270 } 271 272 /** @hide */ 273 @Override writeToParcel(@onNull Parcel dest, int flags)274 public void writeToParcel(@NonNull Parcel dest, int flags) { 275 dest.writeStrongBinder(mFragmentToken); 276 dest.writeTypedObject(mToken, flags); 277 mConfiguration.writeToParcel(dest, flags); 278 dest.writeInt(mRunningActivityCount); 279 dest.writeBoolean(mIsVisible); 280 dest.writeBinderList(mActivities); 281 dest.writeBinderList(mInRequestedTaskFragmentActivities); 282 mPositionInParent.writeToParcel(dest, flags); 283 dest.writeBoolean(mIsTaskClearedForReuse); 284 dest.writeBoolean(mIsTaskFragmentClearedForPip); 285 dest.writeBoolean(mIsClearedForReorderActivityToFront); 286 mMinimumDimensions.writeToParcel(dest, flags); 287 dest.writeBoolean(mIsTopNonFishingChild); 288 } 289 290 @NonNull 291 public static final Creator<TaskFragmentInfo> CREATOR = 292 new Creator<TaskFragmentInfo>() { 293 @Override 294 public TaskFragmentInfo createFromParcel(Parcel in) { 295 return new TaskFragmentInfo(in); 296 } 297 298 @Override 299 public TaskFragmentInfo[] newArray(int size) { 300 return new TaskFragmentInfo[size]; 301 } 302 }; 303 304 @Override toString()305 public String toString() { 306 return "TaskFragmentInfo{" 307 + " fragmentToken=" + mFragmentToken 308 + " token=" + mToken 309 + " runningActivityCount=" + mRunningActivityCount 310 + " isVisible=" + mIsVisible 311 + " activities=" + mActivities 312 + " inRequestedTaskFragmentActivities" + mInRequestedTaskFragmentActivities 313 + " positionInParent=" + mPositionInParent 314 + " isTaskClearedForReuse=" + mIsTaskClearedForReuse 315 + " isTaskFragmentClearedForPip=" + mIsTaskFragmentClearedForPip 316 + " mIsClearedForReorderActivityToFront=" + mIsClearedForReorderActivityToFront 317 + " minimumDimensions=" + mMinimumDimensions 318 + " isTopNonFinishingChild=" + mIsTopNonFishingChild 319 + "}"; 320 } 321 322 /** @hide */ 323 @Override describeContents()324 public int describeContents() { 325 return 0; 326 } 327 } 328