/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.window; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.res.Configuration; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.Point; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.view.Surface; import android.view.WindowInsetsController; /** * Represents a task snapshot. * @hide */ public class TaskSnapshot implements Parcelable { // Identifier of this snapshot private final long mId; // Top activity in task when snapshot was taken private final ComponentName mTopActivityComponent; private final HardwareBuffer mSnapshot; /** Indicates whether task was in landscape or portrait */ @Configuration.Orientation private final int mOrientation; /** See {@link android.view.Surface.Rotation} */ @Surface.Rotation private final int mRotation; /** The size of the snapshot before scaling */ private final Point mTaskSize; private final Rect mContentInsets; // Whether this snapshot is a down-sampled version of the high resolution snapshot, used // mainly for loading snapshots quickly from disk when user is flinging fast private final boolean mIsLowResolution; // Whether or not the snapshot is a real snapshot or an app-theme generated snapshot due to // the task having a secure window or having previews disabled private final boolean mIsRealSnapshot; private final int mWindowingMode; private final @WindowInsetsController.Appearance int mAppearance; private final boolean mIsTranslucent; private final boolean mHasImeSurface; // Must be one of the named color spaces, otherwise, always use SRGB color space. private final ColorSpace mColorSpace; public TaskSnapshot(long id, @NonNull ComponentName topActivityComponent, HardwareBuffer snapshot, @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize, Rect contentInsets, boolean isLowResolution, boolean isRealSnapshot, int windowingMode, @WindowInsetsController.Appearance int appearance, boolean isTranslucent, boolean hasImeSurface) { mId = id; mTopActivityComponent = topActivityComponent; mSnapshot = snapshot; mColorSpace = colorSpace.getId() < 0 ? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace; mOrientation = orientation; mRotation = rotation; mTaskSize = new Point(taskSize); mContentInsets = new Rect(contentInsets); mIsLowResolution = isLowResolution; mIsRealSnapshot = isRealSnapshot; mWindowingMode = windowingMode; mAppearance = appearance; mIsTranslucent = isTranslucent; mHasImeSurface = hasImeSurface; } private TaskSnapshot(Parcel source) { mId = source.readLong(); mTopActivityComponent = ComponentName.readFromParcel(source); mSnapshot = source.readTypedObject(HardwareBuffer.CREATOR); int colorSpaceId = source.readInt(); mColorSpace = colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length ? ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]) : ColorSpace.get(ColorSpace.Named.SRGB); mOrientation = source.readInt(); mRotation = source.readInt(); mTaskSize = source.readTypedObject(Point.CREATOR); mContentInsets = source.readTypedObject(Rect.CREATOR); mIsLowResolution = source.readBoolean(); mIsRealSnapshot = source.readBoolean(); mWindowingMode = source.readInt(); mAppearance = source.readInt(); mIsTranslucent = source.readBoolean(); mHasImeSurface = source.readBoolean(); } /** * @return Identifier of this snapshot. */ public long getId() { return mId; } /** * @return The top activity component for the task at the point this snapshot was taken. */ public ComponentName getTopActivityComponent() { return mTopActivityComponent; } /** * @return The graphic buffer representing the screenshot. * * Note: Prefer {@link #getHardwareBuffer}, which returns the internal object. This version * creates a new object. */ @UnsupportedAppUsage public GraphicBuffer getSnapshot() { return GraphicBuffer.createFromHardwareBuffer(mSnapshot); } /** * @return The hardware buffer representing the screenshot. */ public HardwareBuffer getHardwareBuffer() { return mSnapshot; } /** * @return The color space of hardware buffer representing the screenshot. */ public ColorSpace getColorSpace() { return mColorSpace; } /** * @return The screen orientation the screenshot was taken in. */ @UnsupportedAppUsage public int getOrientation() { return mOrientation; } /** * @return The screen rotation the screenshot was taken in. */ public int getRotation() { return mRotation; } /** * @return The size of the task at the point this snapshot was taken. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Point getTaskSize() { return mTaskSize; } /** * @return The system/content insets on the snapshot. These can be clipped off in order to * remove any areas behind system bars in the snapshot. */ @UnsupportedAppUsage public Rect getContentInsets() { return mContentInsets; } /** * @return Whether this snapshot is a down-sampled version of the full resolution. */ @UnsupportedAppUsage public boolean isLowResolution() { return mIsLowResolution; } /** * @return Whether or not the snapshot is a real snapshot or an app-theme generated snapshot * due to the task having a secure window or having previews disabled. */ @UnsupportedAppUsage public boolean isRealSnapshot() { return mIsRealSnapshot; } /** * @return Whether or not the snapshot is of a translucent app window (non-fullscreen or has * a non-opaque pixel format). */ public boolean isTranslucent() { return mIsTranslucent; } /** * @return Whether or not the snapshot has the IME surface. */ public boolean hasImeSurface() { return mHasImeSurface; } /** * @return The windowing mode of the task when this snapshot was taken. */ public int getWindowingMode() { return mWindowingMode; } /** * @return The {@link WindowInsetsController.Appearance} flags for the top most visible * fullscreen window at the time that the snapshot was taken. */ public @WindowInsetsController.Appearance int getAppearance() { return mAppearance; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(mId); ComponentName.writeToParcel(mTopActivityComponent, dest); dest.writeTypedObject(mSnapshot != null && !mSnapshot.isClosed() ? mSnapshot : null, 0); dest.writeInt(mColorSpace.getId()); dest.writeInt(mOrientation); dest.writeInt(mRotation); dest.writeTypedObject(mTaskSize, 0); dest.writeTypedObject(mContentInsets, 0); dest.writeBoolean(mIsLowResolution); dest.writeBoolean(mIsRealSnapshot); dest.writeInt(mWindowingMode); dest.writeInt(mAppearance); dest.writeBoolean(mIsTranslucent); dest.writeBoolean(mHasImeSurface); } @Override public String toString() { final int width = mSnapshot != null ? mSnapshot.getWidth() : 0; final int height = mSnapshot != null ? mSnapshot.getHeight() : 0; return "TaskSnapshot{" + " mId=" + mId + " mTopActivityComponent=" + mTopActivityComponent.flattenToShortString() + " mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")" + " mColorSpace=" + mColorSpace.toString() + " mOrientation=" + mOrientation + " mRotation=" + mRotation + " mTaskSize=" + mTaskSize.toString() + " mContentInsets=" + mContentInsets.toShortString() + " mIsLowResolution=" + mIsLowResolution + " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode + " mAppearance=" + mAppearance + " mIsTranslucent=" + mIsTranslucent + " mHasImeSurface=" + mHasImeSurface; } public static final @NonNull Creator CREATOR = new Creator() { public TaskSnapshot createFromParcel(Parcel source) { return new TaskSnapshot(source); } public TaskSnapshot[] newArray(int size) { return new TaskSnapshot[size]; } }; /** Builder for a {@link TaskSnapshot} object */ public static final class Builder { private long mId; private ComponentName mTopActivity; private HardwareBuffer mSnapshot; private ColorSpace mColorSpace; private int mOrientation; private int mRotation; private Point mTaskSize; private Rect mContentInsets; private boolean mIsRealSnapshot; private int mWindowingMode; private @WindowInsetsController.Appearance int mAppearance; private boolean mIsTranslucent; private boolean mHasImeSurface; private int mPixelFormat; public Builder setId(long id) { mId = id; return this; } public Builder setTopActivityComponent(ComponentName name) { mTopActivity = name; return this; } public Builder setSnapshot(HardwareBuffer buffer) { mSnapshot = buffer; return this; } public Builder setColorSpace(ColorSpace colorSpace) { mColorSpace = colorSpace; return this; } public Builder setOrientation(int orientation) { mOrientation = orientation; return this; } public Builder setRotation(int rotation) { mRotation = rotation; return this; } /** * Sets the original size of the task */ public Builder setTaskSize(Point size) { mTaskSize = size; return this; } public Builder setContentInsets(Rect contentInsets) { mContentInsets = contentInsets; return this; } public Builder setIsRealSnapshot(boolean realSnapshot) { mIsRealSnapshot = realSnapshot; return this; } public Builder setWindowingMode(int windowingMode) { mWindowingMode = windowingMode; return this; } public Builder setAppearance(@WindowInsetsController.Appearance int appearance) { mAppearance = appearance; return this; } public Builder setIsTranslucent(boolean isTranslucent) { mIsTranslucent = isTranslucent; return this; } /** * Sets the IME visibility when taking the snapshot of the task. */ public Builder setHasImeSurface(boolean hasImeSurface) { mHasImeSurface = hasImeSurface; return this; } public int getPixelFormat() { return mPixelFormat; } public Builder setPixelFormat(int pixelFormat) { mPixelFormat = pixelFormat; return this; } public TaskSnapshot build() { return new TaskSnapshot( mId, mTopActivity, mSnapshot, mColorSpace, mOrientation, mRotation, mTaskSize, mContentInsets, // When building a TaskSnapshot with the Builder class, isLowResolution // is always false. Low-res snapshots are only created when loading from // disk. false /* isLowResolution */, mIsRealSnapshot, mWindowingMode, mAppearance, mIsTranslucent, mHasImeSurface); } } }