1 /*
2  * Copyright (C) 2022 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.view;
18 
19 import static android.view.Display.INVALID_DISPLAY;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.os.IBinder;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import com.android.internal.util.DataClass;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 
33 /**
34  * Description of a content recording session.
35  *
36  * @hide
37  */
38 @DataClass(
39         genConstructor = false,
40         genToString = true,
41         genSetters = true,
42         genEqualsHashCode = true
43 )
44 public final class ContentRecordingSession implements Parcelable {
45 
46     /**
47      * An entire DisplayContent is being recorded. Recording may also be paused.
48      */
49     public static final int RECORD_CONTENT_DISPLAY = 0;
50     /**
51      * A single Task is being recorded. Recording may also be paused.
52      */
53     public static final int RECORD_CONTENT_TASK = 1;
54 
55     /**
56      * Unique logical identifier of the {@link android.hardware.display.VirtualDisplay} that has
57      * recorded content rendered to its surface.
58      */
59     private int mVirtualDisplayId = INVALID_DISPLAY;
60 
61     /**
62      * The content to record.
63      */
64     @RecordContent
65     private int mContentToRecord = RECORD_CONTENT_DISPLAY;
66 
67     /**
68      * Unique logical identifier of the {@link android.view.Display} to record.
69      *
70      * <p>If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_DISPLAY}, then is
71      * a valid display id.
72      */
73     private int mDisplayToRecord = INVALID_DISPLAY;
74 
75     /**
76      * The token of the layer of the hierarchy to record.
77      *
78      * <p>If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
79      * represents the {@link android.window.WindowContainerToken} of the Task to record.
80      */
81     @Nullable
82     private IBinder mTokenToRecord = null;
83 
84     /**
85      * When {@code true}, no mirroring should take place until the user has re-granted access to
86      * the consent token. When {@code false}, recording can begin immediately.
87      *
88      * <p>Only set on the server side to sanitize any input from the client process.
89      */
90     private boolean mWaitingForConsent = false;
91 
92     /**
93      * Default instance, with recording the display.
94      */
ContentRecordingSession()95     private ContentRecordingSession() {
96     }
97 
98     /**
99      * Returns an instance initialized for recording the indicated display.
100      */
createDisplaySession(int displayToMirror)101     public static ContentRecordingSession createDisplaySession(int displayToMirror) {
102         return new ContentRecordingSession().setDisplayToRecord(displayToMirror)
103                 .setContentToRecord(RECORD_CONTENT_DISPLAY);
104     }
105 
106     /**
107      * Returns an instance initialized for task recording.
108      */
createTaskSession( @onNull IBinder taskWindowContainerToken)109     public static ContentRecordingSession createTaskSession(
110             @NonNull IBinder taskWindowContainerToken) {
111         return new ContentRecordingSession().setContentToRecord(RECORD_CONTENT_TASK)
112                 .setTokenToRecord(taskWindowContainerToken);
113     }
114 
115     /**
116      * Returns {@code true} if this is a valid session.
117      *
118      * <p>A valid session has a non-null token for task recording, or a valid id for the display to
119      * record.
120      */
isValid(ContentRecordingSession session)121     public static boolean isValid(ContentRecordingSession session) {
122         if (session == null) {
123             return false;
124         }
125         final boolean isValidTaskSession = session.getContentToRecord() == RECORD_CONTENT_TASK
126                 && session.getTokenToRecord() != null;
127         final boolean isValidDisplaySession = session.getContentToRecord() == RECORD_CONTENT_DISPLAY
128                 && session.getDisplayToRecord() > INVALID_DISPLAY;
129         return session.getVirtualDisplayId() > INVALID_DISPLAY
130                 && (isValidTaskSession || isValidDisplaySession);
131     }
132 
133     /**
134      * Returns {@code true} when both sessions are on the same
135      * {@link android.hardware.display.VirtualDisplay}.
136      */
isProjectionOnSameDisplay(ContentRecordingSession session, ContentRecordingSession incomingSession)137     public static boolean isProjectionOnSameDisplay(ContentRecordingSession session,
138             ContentRecordingSession incomingSession) {
139         return session != null && incomingSession != null
140                 && session.getVirtualDisplayId() == incomingSession.getVirtualDisplayId();
141     }
142 
143 
144 
145 
146     // Code below generated by codegen v1.0.23.
147     //
148     // DO NOT MODIFY!
149     // CHECKSTYLE:OFF Generated code
150     //
151     // To regenerate run:
152     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/ContentRecordingSession.java
153     //
154     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
155     //   Settings > Editor > Code Style > Formatter Control
156     //@formatter:off
157 
158 
159     @IntDef(prefix = "RECORD_CONTENT_", value = {
160         RECORD_CONTENT_DISPLAY,
161         RECORD_CONTENT_TASK
162     })
163     @Retention(RetentionPolicy.SOURCE)
164     @DataClass.Generated.Member
165     public @interface RecordContent {}
166 
167     @DataClass.Generated.Member
recordContentToString(@ecordContent int value)168     public static String recordContentToString(@RecordContent int value) {
169         switch (value) {
170             case RECORD_CONTENT_DISPLAY:
171                     return "RECORD_CONTENT_DISPLAY";
172             case RECORD_CONTENT_TASK:
173                     return "RECORD_CONTENT_TASK";
174             default: return Integer.toHexString(value);
175         }
176     }
177 
178     @DataClass.Generated.Member
ContentRecordingSession( int virtualDisplayId, @RecordContent int contentToRecord, int displayToRecord, @Nullable IBinder tokenToRecord, boolean waitingForConsent)179     /* package-private */ ContentRecordingSession(
180             int virtualDisplayId,
181             @RecordContent int contentToRecord,
182             int displayToRecord,
183             @Nullable IBinder tokenToRecord,
184             boolean waitingForConsent) {
185         this.mVirtualDisplayId = virtualDisplayId;
186         this.mContentToRecord = contentToRecord;
187 
188         if (!(mContentToRecord == RECORD_CONTENT_DISPLAY)
189                 && !(mContentToRecord == RECORD_CONTENT_TASK)) {
190             throw new java.lang.IllegalArgumentException(
191                     "contentToRecord was " + mContentToRecord + " but must be one of: "
192                             + "RECORD_CONTENT_DISPLAY(" + RECORD_CONTENT_DISPLAY + "), "
193                             + "RECORD_CONTENT_TASK(" + RECORD_CONTENT_TASK + ")");
194         }
195 
196         this.mDisplayToRecord = displayToRecord;
197         this.mTokenToRecord = tokenToRecord;
198         this.mWaitingForConsent = waitingForConsent;
199 
200         // onConstructed(); // You can define this method to get a callback
201     }
202 
203     /**
204      * Unique logical identifier of the {@link android.hardware.display.VirtualDisplay} that has
205      * recorded content rendered to its surface.
206      */
207     @DataClass.Generated.Member
getVirtualDisplayId()208     public int getVirtualDisplayId() {
209         return mVirtualDisplayId;
210     }
211 
212     /**
213      * The content to record.
214      */
215     @DataClass.Generated.Member
getContentToRecord()216     public @RecordContent int getContentToRecord() {
217         return mContentToRecord;
218     }
219 
220     /**
221      * Unique logical identifier of the {@link android.view.Display} to record.
222      *
223      * <p>If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_DISPLAY}, then is
224      * a valid display id.
225      */
226     @DataClass.Generated.Member
getDisplayToRecord()227     public int getDisplayToRecord() {
228         return mDisplayToRecord;
229     }
230 
231     /**
232      * The token of the layer of the hierarchy to record.
233      *
234      * <p>If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
235      * represents the {@link android.window.WindowContainerToken} of the Task to record.
236      */
237     @DataClass.Generated.Member
getTokenToRecord()238     public @Nullable IBinder getTokenToRecord() {
239         return mTokenToRecord;
240     }
241 
242     /**
243      * When {@code true}, no mirroring should take place until the user has re-granted access to
244      * the consent token. When {@code false}, recording can begin immediately.
245      *
246      * <p>Only set on the server side to sanitize any input from the client process.
247      */
248     @DataClass.Generated.Member
isWaitingForConsent()249     public boolean isWaitingForConsent() {
250         return mWaitingForConsent;
251     }
252 
253     /**
254      * Unique logical identifier of the {@link android.hardware.display.VirtualDisplay} that has
255      * recorded content rendered to its surface.
256      */
257     @DataClass.Generated.Member
setVirtualDisplayId( int value)258     public @NonNull ContentRecordingSession setVirtualDisplayId( int value) {
259         mVirtualDisplayId = value;
260         return this;
261     }
262 
263     /**
264      * The content to record.
265      */
266     @DataClass.Generated.Member
setContentToRecord(@ecordContent int value)267     public @NonNull ContentRecordingSession setContentToRecord(@RecordContent int value) {
268         mContentToRecord = value;
269 
270         if (!(mContentToRecord == RECORD_CONTENT_DISPLAY)
271                 && !(mContentToRecord == RECORD_CONTENT_TASK)) {
272             throw new java.lang.IllegalArgumentException(
273                     "contentToRecord was " + mContentToRecord + " but must be one of: "
274                             + "RECORD_CONTENT_DISPLAY(" + RECORD_CONTENT_DISPLAY + "), "
275                             + "RECORD_CONTENT_TASK(" + RECORD_CONTENT_TASK + ")");
276         }
277 
278         return this;
279     }
280 
281     /**
282      * Unique logical identifier of the {@link android.view.Display} to record.
283      *
284      * <p>If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_DISPLAY}, then is
285      * a valid display id.
286      */
287     @DataClass.Generated.Member
setDisplayToRecord( int value)288     public @NonNull ContentRecordingSession setDisplayToRecord( int value) {
289         mDisplayToRecord = value;
290         return this;
291     }
292 
293     /**
294      * The token of the layer of the hierarchy to record.
295      *
296      * <p>If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
297      * represents the {@link android.window.WindowContainerToken} of the Task to record.
298      */
299     @DataClass.Generated.Member
setTokenToRecord(@onNull IBinder value)300     public @NonNull ContentRecordingSession setTokenToRecord(@NonNull IBinder value) {
301         mTokenToRecord = value;
302         return this;
303     }
304 
305     /**
306      * When {@code true}, no mirroring should take place until the user has re-granted access to
307      * the consent token. When {@code false}, recording can begin immediately.
308      *
309      * <p>Only set on the server side to sanitize any input from the client process.
310      */
311     @DataClass.Generated.Member
setWaitingForConsent( boolean value)312     public @NonNull ContentRecordingSession setWaitingForConsent( boolean value) {
313         mWaitingForConsent = value;
314         return this;
315     }
316 
317     @Override
318     @DataClass.Generated.Member
toString()319     public String toString() {
320         // You can override field toString logic by defining methods like:
321         // String fieldNameToString() { ... }
322 
323         return "ContentRecordingSession { " +
324                 "virtualDisplayId = " + mVirtualDisplayId + ", " +
325                 "contentToRecord = " + recordContentToString(mContentToRecord) + ", " +
326                 "displayToRecord = " + mDisplayToRecord + ", " +
327                 "tokenToRecord = " + mTokenToRecord + ", " +
328                 "waitingForConsent = " + mWaitingForConsent +
329         " }";
330     }
331 
332     @Override
333     @DataClass.Generated.Member
equals(@ullable Object o)334     public boolean equals(@Nullable Object o) {
335         // You can override field equality logic by defining either of the methods like:
336         // boolean fieldNameEquals(ContentRecordingSession other) { ... }
337         // boolean fieldNameEquals(FieldType otherValue) { ... }
338 
339         if (this == o) return true;
340         if (o == null || getClass() != o.getClass()) return false;
341         @SuppressWarnings("unchecked")
342         ContentRecordingSession that = (ContentRecordingSession) o;
343         //noinspection PointlessBooleanExpression
344         return true
345                 && mVirtualDisplayId == that.mVirtualDisplayId
346                 && mContentToRecord == that.mContentToRecord
347                 && mDisplayToRecord == that.mDisplayToRecord
348                 && java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord)
349                 && mWaitingForConsent == that.mWaitingForConsent;
350     }
351 
352     @Override
353     @DataClass.Generated.Member
hashCode()354     public int hashCode() {
355         // You can override field hashCode logic by defining methods like:
356         // int fieldNameHashCode() { ... }
357 
358         int _hash = 1;
359         _hash = 31 * _hash + mVirtualDisplayId;
360         _hash = 31 * _hash + mContentToRecord;
361         _hash = 31 * _hash + mDisplayToRecord;
362         _hash = 31 * _hash + java.util.Objects.hashCode(mTokenToRecord);
363         _hash = 31 * _hash + Boolean.hashCode(mWaitingForConsent);
364         return _hash;
365     }
366 
367     @Override
368     @DataClass.Generated.Member
writeToParcel(@onNull Parcel dest, int flags)369     public void writeToParcel(@NonNull Parcel dest, int flags) {
370         // You can override field parcelling by defining methods like:
371         // void parcelFieldName(Parcel dest, int flags) { ... }
372 
373         byte flg = 0;
374         if (mWaitingForConsent) flg |= 0x10;
375         if (mTokenToRecord != null) flg |= 0x8;
376         dest.writeByte(flg);
377         dest.writeInt(mVirtualDisplayId);
378         dest.writeInt(mContentToRecord);
379         dest.writeInt(mDisplayToRecord);
380         if (mTokenToRecord != null) dest.writeStrongBinder(mTokenToRecord);
381     }
382 
383     @Override
384     @DataClass.Generated.Member
describeContents()385     public int describeContents() { return 0; }
386 
387     /** @hide */
388     @SuppressWarnings({"unchecked", "RedundantCast"})
389     @DataClass.Generated.Member
ContentRecordingSession(@onNull Parcel in)390     /* package-private */ ContentRecordingSession(@NonNull Parcel in) {
391         // You can override field unparcelling by defining methods like:
392         // static FieldType unparcelFieldName(Parcel in) { ... }
393 
394         byte flg = in.readByte();
395         boolean waitingForConsent = (flg & 0x10) != 0;
396         int virtualDisplayId = in.readInt();
397         int contentToRecord = in.readInt();
398         int displayToRecord = in.readInt();
399         IBinder tokenToRecord = (flg & 0x8) == 0 ? null : (IBinder) in.readStrongBinder();
400 
401         this.mVirtualDisplayId = virtualDisplayId;
402         this.mContentToRecord = contentToRecord;
403 
404         if (!(mContentToRecord == RECORD_CONTENT_DISPLAY)
405                 && !(mContentToRecord == RECORD_CONTENT_TASK)) {
406             throw new java.lang.IllegalArgumentException(
407                     "contentToRecord was " + mContentToRecord + " but must be one of: "
408                             + "RECORD_CONTENT_DISPLAY(" + RECORD_CONTENT_DISPLAY + "), "
409                             + "RECORD_CONTENT_TASK(" + RECORD_CONTENT_TASK + ")");
410         }
411 
412         this.mDisplayToRecord = displayToRecord;
413         this.mTokenToRecord = tokenToRecord;
414         this.mWaitingForConsent = waitingForConsent;
415 
416         // onConstructed(); // You can define this method to get a callback
417     }
418 
419     @DataClass.Generated.Member
420     public static final @NonNull Parcelable.Creator<ContentRecordingSession> CREATOR
421             = new Parcelable.Creator<ContentRecordingSession>() {
422         @Override
423         public ContentRecordingSession[] newArray(int size) {
424             return new ContentRecordingSession[size];
425         }
426 
427         @Override
428         public ContentRecordingSession createFromParcel(@NonNull Parcel in) {
429             return new ContentRecordingSession(in);
430         }
431     };
432 
433     /**
434      * A builder for {@link ContentRecordingSession}
435      */
436     @SuppressWarnings("WeakerAccess")
437     @DataClass.Generated.Member
438     public static final class Builder {
439 
440         private int mVirtualDisplayId;
441         private @RecordContent int mContentToRecord;
442         private int mDisplayToRecord;
443         private @Nullable IBinder mTokenToRecord;
444         private boolean mWaitingForConsent;
445 
446         private long mBuilderFieldsSet = 0L;
447 
Builder()448         public Builder() {
449         }
450 
451         /**
452          * Unique logical identifier of the {@link android.hardware.display.VirtualDisplay} that has
453          * recorded content rendered to its surface.
454          */
455         @DataClass.Generated.Member
setVirtualDisplayId(int value)456         public @NonNull Builder setVirtualDisplayId(int value) {
457             checkNotUsed();
458             mBuilderFieldsSet |= 0x1;
459             mVirtualDisplayId = value;
460             return this;
461         }
462 
463         /**
464          * The content to record.
465          */
466         @DataClass.Generated.Member
setContentToRecord(@ecordContent int value)467         public @NonNull Builder setContentToRecord(@RecordContent int value) {
468             checkNotUsed();
469             mBuilderFieldsSet |= 0x2;
470             mContentToRecord = value;
471             return this;
472         }
473 
474         /**
475          * Unique logical identifier of the {@link android.view.Display} to record.
476          *
477          * <p>If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_DISPLAY}, then is
478          * a valid display id.
479          */
480         @DataClass.Generated.Member
setDisplayToRecord(int value)481         public @NonNull Builder setDisplayToRecord(int value) {
482             checkNotUsed();
483             mBuilderFieldsSet |= 0x4;
484             mDisplayToRecord = value;
485             return this;
486         }
487 
488         /**
489          * The token of the layer of the hierarchy to record.
490          *
491          * <p>If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
492          * represents the {@link android.window.WindowContainerToken} of the Task to record.
493          */
494         @DataClass.Generated.Member
setTokenToRecord(@onNull IBinder value)495         public @NonNull Builder setTokenToRecord(@NonNull IBinder value) {
496             checkNotUsed();
497             mBuilderFieldsSet |= 0x8;
498             mTokenToRecord = value;
499             return this;
500         }
501 
502         /**
503          * When {@code true}, no mirroring should take place until the user has re-granted access to
504          * the consent token. When {@code false}, recording can begin immediately.
505          *
506          * <p>Only set on the server side to sanitize any input from the client process.
507          */
508         @DataClass.Generated.Member
setWaitingForConsent(boolean value)509         public @NonNull Builder setWaitingForConsent(boolean value) {
510             checkNotUsed();
511             mBuilderFieldsSet |= 0x10;
512             mWaitingForConsent = value;
513             return this;
514         }
515 
516         /** Builds the instance. This builder should not be touched after calling this! */
build()517         public @NonNull ContentRecordingSession build() {
518             checkNotUsed();
519             mBuilderFieldsSet |= 0x20; // Mark builder used
520 
521             if ((mBuilderFieldsSet & 0x1) == 0) {
522                 mVirtualDisplayId = INVALID_DISPLAY;
523             }
524             if ((mBuilderFieldsSet & 0x2) == 0) {
525                 mContentToRecord = RECORD_CONTENT_DISPLAY;
526             }
527             if ((mBuilderFieldsSet & 0x4) == 0) {
528                 mDisplayToRecord = INVALID_DISPLAY;
529             }
530             if ((mBuilderFieldsSet & 0x8) == 0) {
531                 mTokenToRecord = null;
532             }
533             if ((mBuilderFieldsSet & 0x10) == 0) {
534                 mWaitingForConsent = false;
535             }
536             ContentRecordingSession o = new ContentRecordingSession(
537                     mVirtualDisplayId,
538                     mContentToRecord,
539                     mDisplayToRecord,
540                     mTokenToRecord,
541                     mWaitingForConsent);
542             return o;
543         }
544 
checkNotUsed()545         private void checkNotUsed() {
546             if ((mBuilderFieldsSet & 0x20) != 0) {
547                 throw new IllegalStateException(
548                         "This Builder should not be reused. Use a new Builder instance instead");
549             }
550         }
551     }
552 
553     @DataClass.Generated(
554             time = 1683628463074L,
555             codegenVersion = "1.0.23",
556             sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java",
557             inputSignatures = "public static final  int RECORD_CONTENT_DISPLAY\npublic static final  int RECORD_CONTENT_TASK\nprivate  int mVirtualDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate  int mDisplayToRecord\nprivate @android.annotation.Nullable android.os.IBinder mTokenToRecord\nprivate  boolean mWaitingForConsent\npublic static  android.view.ContentRecordingSession createDisplaySession(int)\npublic static  android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static  boolean isValid(android.view.ContentRecordingSession)\npublic static  boolean isProjectionOnSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)")
558     @Deprecated
__metadata()559     private void __metadata() {}
560 
561 
562     //@formatter:on
563     // End of generated code
564 
565 }
566