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