1 /* 2 * Copyright (C) 2020 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 android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.content.ComponentName; 23 import android.content.res.Configuration; 24 import android.graphics.ColorSpace; 25 import android.graphics.GraphicBuffer; 26 import android.graphics.Point; 27 import android.graphics.Rect; 28 import android.hardware.HardwareBuffer; 29 import android.os.Build; 30 import android.os.Parcel; 31 import android.os.Parcelable; 32 import android.os.SystemClock; 33 import android.view.Surface; 34 import android.view.WindowInsetsController; 35 36 import com.android.window.flags.Flags; 37 38 import java.lang.annotation.Retention; 39 import java.lang.annotation.RetentionPolicy; 40 41 /** 42 * Represents a task snapshot. 43 * @hide 44 */ 45 public class TaskSnapshot implements Parcelable { 46 // Identifier of this snapshot 47 private final long mId; 48 // The elapsed real time (in nanoseconds) when this snapshot was captured, not intended for use outside the 49 // process in which the snapshot was taken (ie. this is not parceled) 50 private final long mCaptureTime; 51 // Top activity in task when snapshot was taken 52 private final ComponentName mTopActivityComponent; 53 private final HardwareBuffer mSnapshot; 54 /** Indicates whether task was in landscape or portrait */ 55 @Configuration.Orientation 56 private final int mOrientation; 57 /** See {@link android.view.Surface.Rotation} */ 58 @Surface.Rotation 59 private final int mRotation; 60 /** The size of the snapshot before scaling */ 61 private final Point mTaskSize; 62 private final Rect mContentInsets; 63 private final Rect mLetterboxInsets; 64 // Whether this snapshot is a down-sampled version of the high resolution snapshot, used 65 // mainly for loading snapshots quickly from disk when user is flinging fast 66 private final boolean mIsLowResolution; 67 // Whether or not the snapshot is a real snapshot or an app-theme generated snapshot due to 68 // the task having a secure window or having previews disabled 69 private final boolean mIsRealSnapshot; 70 private final int mWindowingMode; 71 private final @WindowInsetsController.Appearance 72 int mAppearance; 73 private final boolean mIsTranslucent; 74 private final boolean mHasImeSurface; 75 // Must be one of the named color spaces, otherwise, always use SRGB color space. 76 private final ColorSpace mColorSpace; 77 private int mInternalReferences; 78 79 /** This snapshot object is being broadcast. */ 80 public static final int REFERENCE_BROADCAST = 1; 81 /** This snapshot object is in the cache. */ 82 public static final int REFERENCE_CACHE = 1 << 1; 83 /** This snapshot object is being persistent. */ 84 public static final int REFERENCE_PERSIST = 1 << 2; 85 @IntDef(flag = true, prefix = { "REFERENCE_" }, value = { 86 REFERENCE_BROADCAST, 87 REFERENCE_CACHE, 88 REFERENCE_PERSIST 89 }) 90 @Retention(RetentionPolicy.SOURCE) 91 @interface ReferenceFlags {} 92 TaskSnapshot(long id, long captureTime, @NonNull ComponentName topActivityComponent, HardwareBuffer snapshot, @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize, Rect contentInsets, Rect letterboxInsets, boolean isLowResolution, boolean isRealSnapshot, int windowingMode, @WindowInsetsController.Appearance int appearance, boolean isTranslucent, boolean hasImeSurface)93 public TaskSnapshot(long id, long captureTime, 94 @NonNull ComponentName topActivityComponent, HardwareBuffer snapshot, 95 @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize, 96 Rect contentInsets, Rect letterboxInsets, boolean isLowResolution, 97 boolean isRealSnapshot, int windowingMode, 98 @WindowInsetsController.Appearance int appearance, boolean isTranslucent, 99 boolean hasImeSurface) { 100 mId = id; 101 mCaptureTime = captureTime; 102 mTopActivityComponent = topActivityComponent; 103 mSnapshot = snapshot; 104 mColorSpace = colorSpace.getId() < 0 105 ? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace; 106 mOrientation = orientation; 107 mRotation = rotation; 108 mTaskSize = new Point(taskSize); 109 mContentInsets = new Rect(contentInsets); 110 mLetterboxInsets = new Rect(letterboxInsets); 111 mIsLowResolution = isLowResolution; 112 mIsRealSnapshot = isRealSnapshot; 113 mWindowingMode = windowingMode; 114 mAppearance = appearance; 115 mIsTranslucent = isTranslucent; 116 mHasImeSurface = hasImeSurface; 117 } 118 119 private TaskSnapshot(Parcel source) { 120 mId = source.readLong(); 121 mCaptureTime = SystemClock.elapsedRealtimeNanos(); 122 mTopActivityComponent = ComponentName.readFromParcel(source); 123 mSnapshot = source.readTypedObject(HardwareBuffer.CREATOR); 124 int colorSpaceId = source.readInt(); 125 mColorSpace = colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length 126 ? ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]) 127 : ColorSpace.get(ColorSpace.Named.SRGB); 128 mOrientation = source.readInt(); 129 mRotation = source.readInt(); 130 mTaskSize = source.readTypedObject(Point.CREATOR); 131 mContentInsets = source.readTypedObject(Rect.CREATOR); 132 mLetterboxInsets = source.readTypedObject(Rect.CREATOR); 133 mIsLowResolution = source.readBoolean(); 134 mIsRealSnapshot = source.readBoolean(); 135 mWindowingMode = source.readInt(); 136 mAppearance = source.readInt(); 137 mIsTranslucent = source.readBoolean(); 138 mHasImeSurface = source.readBoolean(); 139 } 140 141 /** 142 * @return Identifier of this snapshot. 143 */ 144 public long getId() { 145 return mId; 146 } 147 148 /** 149 * @return The elapsed real time (in nanoseconds) when this snapshot was captured. This time is 150 * only valid in the process where this snapshot was taken. 151 */ 152 public long getCaptureTime() { 153 return mCaptureTime; 154 } 155 156 /** 157 * @return The top activity component for the task at the point this snapshot was taken. 158 */ 159 public ComponentName getTopActivityComponent() { 160 return mTopActivityComponent; 161 } 162 163 /** 164 * @return The graphic buffer representing the screenshot. 165 * 166 * Note: Prefer {@link #getHardwareBuffer}, which returns the internal object. This version 167 * creates a new object. 168 */ 169 @UnsupportedAppUsage 170 public GraphicBuffer getSnapshot() { 171 return GraphicBuffer.createFromHardwareBuffer(mSnapshot); 172 } 173 174 /** 175 * @return The hardware buffer representing the screenshot. 176 */ 177 public HardwareBuffer getHardwareBuffer() { 178 return mSnapshot; 179 } 180 181 /** 182 * @return The color space of hardware buffer representing the screenshot. 183 */ 184 public ColorSpace getColorSpace() { 185 return mColorSpace; 186 } 187 188 /** 189 * @return The screen orientation the screenshot was taken in. 190 */ 191 @UnsupportedAppUsage 192 public int getOrientation() { 193 return mOrientation; 194 } 195 196 /** 197 * @return The screen rotation the screenshot was taken in. 198 */ 199 public int getRotation() { 200 return mRotation; 201 } 202 203 /** 204 * @return The size of the task at the point this snapshot was taken. 205 */ 206 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 207 public Point getTaskSize() { 208 return mTaskSize; 209 } 210 211 /** 212 * @return The system/content insets on the snapshot. These can be clipped off in order to 213 * remove any areas behind system bars in the snapshot. 214 */ 215 @UnsupportedAppUsage 216 public Rect getContentInsets() { 217 return mContentInsets; 218 } 219 220 /** 221 * @return The letterbox insets on the snapshot. These can be clipped off in order to 222 * remove any letterbox areas in the snapshot. 223 */ 224 public Rect getLetterboxInsets() { 225 return mLetterboxInsets; 226 } 227 228 /** 229 * @return Whether this snapshot is a down-sampled version of the full resolution. 230 */ 231 @UnsupportedAppUsage 232 public boolean isLowResolution() { 233 return mIsLowResolution; 234 } 235 236 /** 237 * @return Whether or not the snapshot is a real snapshot or an app-theme generated snapshot 238 * due to the task having a secure window or having previews disabled. 239 */ 240 @UnsupportedAppUsage 241 public boolean isRealSnapshot() { 242 return mIsRealSnapshot; 243 } 244 245 /** 246 * @return Whether or not the snapshot is of a translucent app window (non-fullscreen or has 247 * a non-opaque pixel format). 248 */ 249 public boolean isTranslucent() { 250 return mIsTranslucent; 251 } 252 253 /** 254 * @return Whether or not the snapshot has the IME surface. 255 */ 256 public boolean hasImeSurface() { 257 return mHasImeSurface; 258 } 259 260 /** 261 * @return The windowing mode of the task when this snapshot was taken. 262 */ 263 public int getWindowingMode() { 264 return mWindowingMode; 265 } 266 267 /** 268 * @return The {@link WindowInsetsController.Appearance} flags for the top most visible 269 * fullscreen window at the time that the snapshot was taken. 270 */ 271 public @WindowInsetsController.Appearance 272 int getAppearance() { 273 return mAppearance; 274 } 275 276 @Override 277 public int describeContents() { 278 return 0; 279 } 280 281 @Override 282 public void writeToParcel(Parcel dest, int flags) { 283 dest.writeLong(mId); 284 ComponentName.writeToParcel(mTopActivityComponent, dest); 285 dest.writeTypedObject(mSnapshot != null && !mSnapshot.isClosed() ? mSnapshot : null, 0); 286 dest.writeInt(mColorSpace.getId()); 287 dest.writeInt(mOrientation); 288 dest.writeInt(mRotation); 289 dest.writeTypedObject(mTaskSize, 0); 290 dest.writeTypedObject(mContentInsets, 0); 291 dest.writeTypedObject(mLetterboxInsets, 0); 292 dest.writeBoolean(mIsLowResolution); 293 dest.writeBoolean(mIsRealSnapshot); 294 dest.writeInt(mWindowingMode); 295 dest.writeInt(mAppearance); 296 dest.writeBoolean(mIsTranslucent); 297 dest.writeBoolean(mHasImeSurface); 298 } 299 300 @Override 301 public String toString() { 302 final int width = mSnapshot != null ? mSnapshot.getWidth() : 0; 303 final int height = mSnapshot != null ? mSnapshot.getHeight() : 0; 304 return "TaskSnapshot{" 305 + " mId=" + mId 306 + " mCaptureTime=" + mCaptureTime 307 + " mTopActivityComponent=" + mTopActivityComponent.flattenToShortString() 308 + " mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")" 309 + " mColorSpace=" + mColorSpace.toString() 310 + " mOrientation=" + mOrientation 311 + " mRotation=" + mRotation 312 + " mTaskSize=" + mTaskSize.toString() 313 + " mContentInsets=" + mContentInsets.toShortString() 314 + " mLetterboxInsets=" + mLetterboxInsets.toShortString() 315 + " mIsLowResolution=" + mIsLowResolution 316 + " mIsRealSnapshot=" + mIsRealSnapshot 317 + " mWindowingMode=" + mWindowingMode 318 + " mAppearance=" + mAppearance 319 + " mIsTranslucent=" + mIsTranslucent 320 + " mHasImeSurface=" + mHasImeSurface 321 + " mInternalReferences=" + mInternalReferences; 322 } 323 324 /** 325 * Adds a reference when the object is held somewhere. 326 * Only used in core. 327 */ 328 public synchronized void addReference(@ReferenceFlags int usage) { 329 mInternalReferences |= usage; 330 } 331 332 /** 333 * Removes a reference when the object is not held from somewhere. The snapshot will be closed 334 * once the reference becomes zero. 335 * Only used in core. 336 */ 337 public synchronized void removeReference(@ReferenceFlags int usage) { 338 mInternalReferences &= ~usage; 339 if (Flags.releaseSnapshotAggressively() && mInternalReferences == 0 && mSnapshot != null 340 && !mSnapshot.isClosed()) { 341 mSnapshot.close(); 342 } 343 } 344 345 public static final @NonNull Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() { 346 public TaskSnapshot createFromParcel(Parcel source) { 347 return new TaskSnapshot(source); 348 } 349 public TaskSnapshot[] newArray(int size) { 350 return new TaskSnapshot[size]; 351 } 352 }; 353 354 /** Builder for a {@link TaskSnapshot} object */ 355 public static final class Builder { 356 private long mId; 357 private long mCaptureTime; 358 private ComponentName mTopActivity; 359 private HardwareBuffer mSnapshot; 360 private ColorSpace mColorSpace; 361 private int mOrientation; 362 private int mRotation; 363 private Point mTaskSize; 364 private Rect mContentInsets; 365 private Rect mLetterboxInsets; 366 private boolean mIsRealSnapshot; 367 private int mWindowingMode; 368 private @WindowInsetsController.Appearance 369 int mAppearance; 370 private boolean mIsTranslucent; 371 private boolean mHasImeSurface; 372 private int mPixelFormat; 373 374 public Builder setId(long id) { 375 mId = id; 376 return this; 377 } 378 379 public Builder setCaptureTime(long captureTime) { 380 mCaptureTime = captureTime; 381 return this; 382 } 383 384 public Builder setTopActivityComponent(ComponentName name) { 385 mTopActivity = name; 386 return this; 387 } 388 389 public Builder setSnapshot(HardwareBuffer buffer) { 390 mSnapshot = buffer; 391 return this; 392 } 393 394 public Builder setColorSpace(ColorSpace colorSpace) { 395 mColorSpace = colorSpace; 396 return this; 397 } 398 399 public Builder setOrientation(int orientation) { 400 mOrientation = orientation; 401 return this; 402 } 403 404 public Builder setRotation(int rotation) { 405 mRotation = rotation; 406 return this; 407 } 408 409 /** 410 * Sets the original size of the task 411 */ 412 public Builder setTaskSize(Point size) { 413 mTaskSize = size; 414 return this; 415 } 416 417 public Builder setContentInsets(Rect contentInsets) { 418 mContentInsets = contentInsets; 419 return this; 420 } 421 422 public Builder setLetterboxInsets(Rect letterboxInsets) { 423 mLetterboxInsets = letterboxInsets; 424 return this; 425 } 426 427 public Builder setIsRealSnapshot(boolean realSnapshot) { 428 mIsRealSnapshot = realSnapshot; 429 return this; 430 } 431 432 public Builder setWindowingMode(int windowingMode) { 433 mWindowingMode = windowingMode; 434 return this; 435 } 436 437 public Builder setAppearance(@WindowInsetsController.Appearance int appearance) { 438 mAppearance = appearance; 439 return this; 440 } 441 442 public Builder setIsTranslucent(boolean isTranslucent) { 443 mIsTranslucent = isTranslucent; 444 return this; 445 } 446 447 /** 448 * Sets the IME visibility when taking the snapshot of the task. 449 */ 450 public Builder setHasImeSurface(boolean hasImeSurface) { 451 mHasImeSurface = hasImeSurface; 452 return this; 453 } 454 455 public int getPixelFormat() { 456 return mPixelFormat; 457 } 458 459 public Builder setPixelFormat(int pixelFormat) { 460 mPixelFormat = pixelFormat; 461 return this; 462 } 463 464 public TaskSnapshot build() { 465 return new TaskSnapshot( 466 mId, 467 mCaptureTime, 468 mTopActivity, 469 mSnapshot, 470 mColorSpace, 471 mOrientation, 472 mRotation, 473 mTaskSize, 474 mContentInsets, 475 mLetterboxInsets, 476 // When building a TaskSnapshot with the Builder class, isLowResolution 477 // is always false. Low-res snapshots are only created when loading from 478 // disk. 479 false /* isLowResolution */, 480 mIsRealSnapshot, 481 mWindowingMode, 482 mAppearance, 483 mIsTranslucent, 484 mHasImeSurface); 485 486 } 487 } 488 } 489