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