• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.IntDef;
20 import android.annotation.NonNull;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.content.ComponentName;
23 import android.content.res.Configuration;
24 import android.graphics.ColorSpace;
25 import android.graphics.GraphicBuffer;
26 import android.graphics.Point;
27 import android.graphics.Rect;
28 import android.hardware.HardwareBuffer;
29 import android.os.Build;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.os.SystemClock;
33 import android.view.Surface;
34 import android.view.WindowInsetsController;
35 
36 import com.android.window.flags.Flags;
37 
38 import java.lang.annotation.Retention;
39 import java.lang.annotation.RetentionPolicy;
40 import java.util.function.Consumer;
41 
42 /**
43  * Represents a task snapshot.
44  * @hide
45  */
46 public class TaskSnapshot implements Parcelable {
47     // Identifier of this snapshot
48     private final long mId;
49     // The elapsed real time (in nanoseconds) when this snapshot was captured, not intended for use outside the
50     // process in which the snapshot was taken (ie. this is not parceled)
51     private final long mCaptureTime;
52     // Top activity in task when snapshot was taken
53     private final ComponentName mTopActivityComponent;
54     private final HardwareBuffer mSnapshot;
55     /** Indicates whether task was in landscape or portrait */
56     @Configuration.Orientation
57     private final int mOrientation;
58     /** See {@link android.view.Surface.Rotation} */
59     @Surface.Rotation
60     private final int mRotation;
61     /** The size of the snapshot before scaling */
62     private final Point mTaskSize;
63     private final Rect mContentInsets;
64     private final Rect mLetterboxInsets;
65     // Whether this snapshot is a down-sampled version of the high resolution snapshot, used
66     // mainly for loading snapshots quickly from disk when user is flinging fast
67     private final boolean mIsLowResolution;
68     // Whether or not the snapshot is a real snapshot or an app-theme generated snapshot due to
69     // the task having a secure window or having previews disabled
70     private final boolean mIsRealSnapshot;
71     private final int mWindowingMode;
72     private final @WindowInsetsController.Appearance
73     int mAppearance;
74     private final boolean mIsTranslucent;
75     private final boolean mHasImeSurface;
76     private final int mUiMode;
77     // Must be one of the named color spaces, otherwise, always use SRGB color space.
78     private final ColorSpace mColorSpace;
79     private int mInternalReferences;
80     private Consumer<HardwareBuffer> mSafeSnapshotReleaser;
81 
82     /** Keep in cache, doesn't need reference. */
83     public static final int REFERENCE_NONE = 0;
84     /** This snapshot object is being broadcast. */
85     public static final int REFERENCE_BROADCAST = 1;
86     /** This snapshot object is in the cache. */
87     public static final int REFERENCE_CACHE = 1 << 1;
88     /** This snapshot object is being persistent. */
89     public static final int REFERENCE_PERSIST = 1 << 2;
90     /** This snapshot object is being used for content suggestion. */
91     public static final int REFERENCE_CONTENT_SUGGESTION = 1 << 3;
92     /** This snapshot object will be passing to external process. Keep the snapshot reference after
93      * writeToParcel*/
94     public static final int REFERENCE_WRITE_TO_PARCEL = 1 << 4;
95     @IntDef(flag = true, prefix = { "REFERENCE_" }, value = {
96             REFERENCE_NONE,
97             REFERENCE_BROADCAST,
98             REFERENCE_CACHE,
99             REFERENCE_PERSIST,
100             REFERENCE_CONTENT_SUGGESTION,
101             REFERENCE_WRITE_TO_PARCEL
102     })
103     @Retention(RetentionPolicy.SOURCE)
104     public @interface ReferenceFlags {}
105 
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, int uiMode)106     public TaskSnapshot(long id, long captureTime,
107             @NonNull ComponentName topActivityComponent, HardwareBuffer snapshot,
108             @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize,
109             Rect contentInsets, Rect letterboxInsets, boolean isLowResolution,
110             boolean isRealSnapshot, int windowingMode,
111             @WindowInsetsController.Appearance int appearance, boolean isTranslucent,
112             boolean hasImeSurface, int uiMode) {
113         mId = id;
114         mCaptureTime = captureTime;
115         mTopActivityComponent = topActivityComponent;
116         mSnapshot = snapshot;
117         mColorSpace = colorSpace.getId() < 0
118                 ? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace;
119         mOrientation = orientation;
120         mRotation = rotation;
121         mTaskSize = new Point(taskSize);
122         mContentInsets = new Rect(contentInsets);
123         mLetterboxInsets = new Rect(letterboxInsets);
124         mIsLowResolution = isLowResolution;
125         mIsRealSnapshot = isRealSnapshot;
126         mWindowingMode = windowingMode;
127         mAppearance = appearance;
128         mIsTranslucent = isTranslucent;
129         mHasImeSurface = hasImeSurface;
130         mUiMode = uiMode;
131     }
132 
133     private TaskSnapshot(Parcel source) {
134         mId = source.readLong();
135         mCaptureTime = SystemClock.elapsedRealtimeNanos();
136         mTopActivityComponent = ComponentName.readFromParcel(source);
137         mSnapshot = source.readTypedObject(HardwareBuffer.CREATOR);
138         int colorSpaceId = source.readInt();
139         mColorSpace = colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length
140                 ? ColorSpace.get(ColorSpace.Named.values()[colorSpaceId])
141                 : ColorSpace.get(ColorSpace.Named.SRGB);
142         mOrientation = source.readInt();
143         mRotation = source.readInt();
144         mTaskSize = source.readTypedObject(Point.CREATOR);
145         mContentInsets = source.readTypedObject(Rect.CREATOR);
146         mLetterboxInsets = source.readTypedObject(Rect.CREATOR);
147         mIsLowResolution = source.readBoolean();
148         mIsRealSnapshot = source.readBoolean();
149         mWindowingMode = source.readInt();
150         mAppearance = source.readInt();
151         mIsTranslucent = source.readBoolean();
152         mHasImeSurface = source.readBoolean();
153         mUiMode = source.readInt();
154     }
155 
156     /**
157      * @return Identifier of this snapshot.
158      */
159     public long getId() {
160         return mId;
161     }
162 
163     /**
164      * @return The elapsed real time (in nanoseconds) when this snapshot was captured. This time is
165      * only valid in the process where this snapshot was taken.
166      */
167     public long getCaptureTime() {
168         return mCaptureTime;
169     }
170 
171     /**
172      * @return The top activity component for the task at the point this snapshot was taken.
173      */
174     public ComponentName getTopActivityComponent() {
175         return mTopActivityComponent;
176     }
177 
178     /**
179      * @return The graphic buffer representing the screenshot.
180      *
181      * Note: Prefer {@link #getHardwareBuffer}, which returns the internal object. This version
182      * creates a new object.
183      */
184     @UnsupportedAppUsage
185     public GraphicBuffer getSnapshot() {
186         return GraphicBuffer.createFromHardwareBuffer(mSnapshot);
187     }
188 
189     /**
190      * @return The hardware buffer representing the screenshot.
191      */
192     public HardwareBuffer getHardwareBuffer() {
193         return mSnapshot;
194     }
195 
196     /**
197      * @return The color space of hardware buffer representing the screenshot.
198      */
199     public ColorSpace getColorSpace() {
200         return mColorSpace;
201     }
202 
203     /**
204      * @return The screen orientation the screenshot was taken in.
205      */
206     @UnsupportedAppUsage
207     public int getOrientation() {
208         return mOrientation;
209     }
210 
211     /**
212      * @return The screen rotation the screenshot was taken in.
213      */
214     public int getRotation() {
215         return mRotation;
216     }
217 
218     /**
219      * @return The size of the task at the point this snapshot was taken.
220      */
221     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
222     public Point getTaskSize() {
223         return mTaskSize;
224     }
225 
226     /**
227      * @return The system/content insets on the snapshot. These can be clipped off in order to
228      *         remove any areas behind system bars in the snapshot.
229      */
230     @UnsupportedAppUsage
231     public Rect getContentInsets() {
232         return mContentInsets;
233     }
234 
235     /**
236      * @return The letterbox insets on the snapshot. These can be clipped off in order to
237      *         remove any letterbox areas in the snapshot.
238      */
239     public Rect getLetterboxInsets() {
240         return mLetterboxInsets;
241     }
242 
243     /**
244      * @return Whether this snapshot is a down-sampled version of the full resolution.
245      */
246     @UnsupportedAppUsage
247     public boolean isLowResolution() {
248         return mIsLowResolution;
249     }
250 
251     /**
252      * @return Whether or not the snapshot is a real snapshot or an app-theme generated snapshot
253      * due to the task having a secure window or having previews disabled.
254      */
255     @UnsupportedAppUsage
256     public boolean isRealSnapshot() {
257         return mIsRealSnapshot;
258     }
259 
260     /**
261      * @return Whether or not the snapshot is of a translucent app window (non-fullscreen or has
262      * a non-opaque pixel format).
263      */
264     public boolean isTranslucent() {
265         return mIsTranslucent;
266     }
267 
268     /**
269      * @return Whether or not the snapshot has the IME surface.
270      */
271     public boolean hasImeSurface() {
272         return mHasImeSurface;
273     }
274 
275     /**
276      * @return The windowing mode of the task when this snapshot was taken.
277      */
278     public int getWindowingMode() {
279         return mWindowingMode;
280     }
281 
282     /**
283      * @return The {@link WindowInsetsController.Appearance} flags for the top most visible
284      *         fullscreen window at the time that the snapshot was taken.
285      */
286     public @WindowInsetsController.Appearance
287     int getAppearance() {
288         return mAppearance;
289     }
290 
291     /**
292      * @return The uiMode the screenshot was taken in.
293      */
294     public int getUiMode() {
295         return mUiMode;
296     }
297 
298     @Override
299     public int describeContents() {
300         return 0;
301     }
302 
303     @Override
304     public void writeToParcel(Parcel dest, int flags) {
305         dest.writeLong(mId);
306         ComponentName.writeToParcel(mTopActivityComponent, dest);
307         dest.writeTypedObject(mSnapshot != null && !mSnapshot.isClosed() ? mSnapshot : null, 0);
308         dest.writeInt(mColorSpace.getId());
309         dest.writeInt(mOrientation);
310         dest.writeInt(mRotation);
311         dest.writeTypedObject(mTaskSize, 0);
312         dest.writeTypedObject(mContentInsets, 0);
313         dest.writeTypedObject(mLetterboxInsets, 0);
314         dest.writeBoolean(mIsLowResolution);
315         dest.writeBoolean(mIsRealSnapshot);
316         dest.writeInt(mWindowingMode);
317         dest.writeInt(mAppearance);
318         dest.writeBoolean(mIsTranslucent);
319         dest.writeBoolean(mHasImeSurface);
320         dest.writeInt(mUiMode);
321         synchronized (this) {
322             if ((mInternalReferences & REFERENCE_WRITE_TO_PARCEL) != 0) {
323                 removeReference(REFERENCE_WRITE_TO_PARCEL);
324             }
325         }
326     }
327 
328     @Override
329     public String toString() {
330         final int width = mSnapshot != null ? mSnapshot.getWidth() : 0;
331         final int height = mSnapshot != null ? mSnapshot.getHeight() : 0;
332         return "TaskSnapshot{"
333                 + " mId=" + mId
334                 + " mCaptureTime=" + mCaptureTime
335                 + " mTopActivityComponent=" + mTopActivityComponent.flattenToShortString()
336                 + " mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")"
337                 + " mColorSpace=" + mColorSpace.toString()
338                 + " mOrientation=" + mOrientation
339                 + " mRotation=" + mRotation
340                 + " mTaskSize=" + mTaskSize.toString()
341                 + " mContentInsets=" + mContentInsets.toShortString()
342                 + " mLetterboxInsets=" + mLetterboxInsets.toShortString()
343                 + " mIsLowResolution=" + mIsLowResolution
344                 + " mIsRealSnapshot=" + mIsRealSnapshot
345                 + " mWindowingMode=" + mWindowingMode
346                 + " mAppearance=" + mAppearance
347                 + " mIsTranslucent=" + mIsTranslucent
348                 + " mHasImeSurface=" + mHasImeSurface
349                 + " mInternalReferences=" + mInternalReferences
350                 + " mUiMode=" + Integer.toHexString(mUiMode);
351     }
352 
353     /**
354      * Adds a reference when the object is held somewhere.
355      * Only used in core.
356      */
357     public synchronized void addReference(@ReferenceFlags int usage) {
358         mInternalReferences |= usage;
359     }
360 
361     /**
362      * Removes a reference when the object is not held from somewhere. The snapshot will be closed
363      * once the reference becomes zero.
364      * Only used in core.
365      */
366     public synchronized void removeReference(@ReferenceFlags int usage) {
367         mInternalReferences &= ~usage;
368         if (Flags.releaseSnapshotAggressively() && mInternalReferences == 0 && mSnapshot != null
369                 && !mSnapshot.isClosed()) {
370             if (mSafeSnapshotReleaser != null) {
371                 mSafeSnapshotReleaser.accept(mSnapshot);
372             } else {
373                 mSnapshot.close();
374             }
375         }
376     }
377 
378     /**
379      * Register a safe release callback, instead of immediately closing the hardware buffer when
380      * no more reference, to let the system server decide when to close it.
381      * Only used in core.
382      */
383     public synchronized void setSafeRelease(Consumer<HardwareBuffer> releaser) {
384         if (!Flags.safeReleaseSnapshotAggressively()) {
385             return;
386         }
387         mSafeSnapshotReleaser = releaser;
388     }
389 
390     public static final @NonNull Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
391         public TaskSnapshot createFromParcel(Parcel source) {
392             return new TaskSnapshot(source);
393         }
394         public TaskSnapshot[] newArray(int size) {
395             return new TaskSnapshot[size];
396         }
397     };
398 
399     /** Builder for a {@link TaskSnapshot} object */
400     public static final class Builder {
401         private long mId;
402         private long mCaptureTime;
403         private ComponentName mTopActivity;
404         private HardwareBuffer mSnapshot;
405         private ColorSpace mColorSpace;
406         private int mOrientation;
407         private int mRotation;
408         private Point mTaskSize;
409         private Rect mContentInsets;
410         private Rect mLetterboxInsets;
411         private boolean mIsRealSnapshot;
412         private int mWindowingMode;
413         private @WindowInsetsController.Appearance
414         int mAppearance;
415         private boolean mIsTranslucent;
416         private boolean mHasImeSurface;
417         private int mPixelFormat;
418         private int mUiMode;
419 
420         public Builder setId(long id) {
421             mId = id;
422             return this;
423         }
424 
425         public Builder setCaptureTime(long captureTime) {
426             mCaptureTime = captureTime;
427             return this;
428         }
429 
430         public Builder setTopActivityComponent(ComponentName name) {
431             mTopActivity = name;
432             return this;
433         }
434 
435         public Builder setSnapshot(HardwareBuffer buffer) {
436             mSnapshot = buffer;
437             return this;
438         }
439 
440         public Builder setColorSpace(ColorSpace colorSpace) {
441             mColorSpace = colorSpace;
442             return this;
443         }
444 
445         public Builder setOrientation(int orientation) {
446             mOrientation = orientation;
447             return this;
448         }
449 
450         public Builder setRotation(int rotation) {
451             mRotation = rotation;
452             return this;
453         }
454 
455         /**
456          * Sets the original size of the task
457          */
458         public Builder setTaskSize(Point size) {
459             mTaskSize = size;
460             return this;
461         }
462 
463         public Builder setContentInsets(Rect contentInsets) {
464             mContentInsets = contentInsets;
465             return this;
466         }
467 
468         public Builder setLetterboxInsets(Rect letterboxInsets) {
469             mLetterboxInsets = letterboxInsets;
470             return this;
471         }
472 
473         public Builder setIsRealSnapshot(boolean realSnapshot) {
474             mIsRealSnapshot = realSnapshot;
475             return this;
476         }
477 
478         public Builder setWindowingMode(int windowingMode) {
479             mWindowingMode = windowingMode;
480             return this;
481         }
482 
483         public Builder setAppearance(@WindowInsetsController.Appearance int appearance) {
484             mAppearance = appearance;
485             return this;
486         }
487 
488         public Builder setIsTranslucent(boolean isTranslucent) {
489             mIsTranslucent = isTranslucent;
490             return this;
491         }
492 
493         /**
494          * Sets the IME visibility when taking the snapshot of the task.
495          */
496         public Builder setHasImeSurface(boolean hasImeSurface) {
497             mHasImeSurface = hasImeSurface;
498             return this;
499         }
500 
501         /**
502          * Sets the original uiMode while capture
503          */
504         public Builder setUiMode(int uiMode) {
505             mUiMode = uiMode;
506             return this;
507         }
508 
509         public int getPixelFormat() {
510             return mPixelFormat;
511         }
512 
513         public Builder setPixelFormat(int pixelFormat) {
514             mPixelFormat = pixelFormat;
515             return this;
516         }
517 
518         public TaskSnapshot build() {
519             return new TaskSnapshot(
520                     mId,
521                     mCaptureTime,
522                     mTopActivity,
523                     mSnapshot,
524                     mColorSpace,
525                     mOrientation,
526                     mRotation,
527                     mTaskSize,
528                     mContentInsets,
529                     mLetterboxInsets,
530                     // When building a TaskSnapshot with the Builder class, isLowResolution
531                     // is always false. Low-res snapshots are only created when loading from
532                     // disk.
533                     false /* isLowResolution */,
534                     mIsRealSnapshot,
535                     mWindowingMode,
536                     mAppearance,
537                     mIsTranslucent,
538                     mHasImeSurface,
539                     mUiMode);
540 
541         }
542     }
543 }
544