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