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