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