• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.companion;
18 
19 import static com.android.internal.util.CollectionUtils.emptyIfNull;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.StringDef;
24 import android.compat.annotation.UnsupportedAppUsage;
25 import android.os.Build;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 import android.provider.OneTimeUseBuilder;
29 
30 import com.android.internal.util.ArrayUtils;
31 import com.android.internal.util.DataClass;
32 
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.Objects;
36 
37 /**
38  * A request for the user to select a companion device to associate with.
39  *
40  * You can optionally set {@link Builder#addDeviceFilter filters} for which devices to show to the
41  * user to select from.
42  * The exact type and fields of the filter you can set depend on the
43  * medium type. See {@link Builder}'s static factory methods for specific protocols that are
44  * supported.
45  *
46  * You can also set {@link Builder#setSingleDevice single device} to request a popup with single
47  * device to be shown instead of a list to choose from
48  */
49 @DataClass(
50         genToString = true,
51         genEqualsHashCode = true,
52         genHiddenGetters = true,
53         genParcelable = true,
54         genHiddenConstructor = true,
55         genBuilder = false)
56 public final class AssociationRequest implements Parcelable {
57 
58     private static final String LOG_TAG = AssociationRequest.class.getSimpleName();
59 
60     /**
61      * Device profile: watch.
62      *
63      * If specified, the current request may have a modified UI to highlight that the device being
64      * set up is a specific kind of device, and some extra permissions may be granted to the app
65      * as a result.
66      *
67      * Using it requires declaring uses-permission
68      * {@link android.Manifest.permission#REQUEST_COMPANION_PROFILE_WATCH} in the manifest.
69      *
70      * <a href="{@docRoot}about/versions/12/features#cdm-profiles">Learn more</a>
71      * about device profiles.
72      *
73      * @see AssociationRequest.Builder#setDeviceProfile
74      */
75     public static final String DEVICE_PROFILE_WATCH = "android.app.role.COMPANION_DEVICE_WATCH";
76 
77     /** @hide */
78     @StringDef(value = { DEVICE_PROFILE_WATCH })
79     public @interface DeviceProfile {}
80 
81     /**
82      * Whether only a single device should match the provided filter.
83      *
84      * When scanning for a single device with a specifc {@link BluetoothDeviceFilter} mac
85      * address, bonded devices are also searched among. This allows to obtain the necessary app
86      * privileges even if the device is already paired.
87      */
88     private boolean mSingleDevice = false;
89 
90     /**
91      * If set, only devices matching either of the given filters will be shown to the user
92      */
93     @DataClass.PluralOf("deviceFilter")
94     private @NonNull List<DeviceFilter<?>> mDeviceFilters = new ArrayList<>();
95 
96     /**
97      * If set, association will be requested as a corresponding kind of device
98      */
99     private @Nullable @DeviceProfile String mDeviceProfile = null;
100 
101     /**
102      * The app package making the request.
103      *
104      * Populated by the system.
105      *
106      * @hide
107      */
108     private @Nullable String mCallingPackage = null;
109 
110     /**
111      * The user-readable description of the device profile's privileges.
112      *
113      * Populated by the system.
114      *
115      * @hide
116      */
117     private @Nullable String mDeviceProfilePrivilegesDescription = null;
118 
119     /**
120      * The time at which his request was created
121      *
122      * @hide
123      */
124     private long mCreationTime;
125 
126     /**
127      * Whether the user-prompt may be skipped once the device is found.
128      *
129      * Populated by the system.
130      *
131      * @hide
132      */
133     private boolean mSkipPrompt = false;
134 
onConstructed()135     private void onConstructed() {
136         mCreationTime = System.currentTimeMillis();
137     }
138 
139     /** @hide */
setCallingPackage(@onNull String pkg)140     public void setCallingPackage(@NonNull String pkg) {
141         mCallingPackage = pkg;
142     }
143 
144     /** @hide */
setDeviceProfilePrivilegesDescription(@onNull String desc)145     public void setDeviceProfilePrivilegesDescription(@NonNull String desc) {
146         mDeviceProfilePrivilegesDescription = desc;
147     }
148 
149     /** @hide */
setSkipPrompt(boolean value)150     public void setSkipPrompt(boolean value) {
151         mSkipPrompt = true;
152     }
153 
154     /** @hide */
155     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isSingleDevice()156     public boolean isSingleDevice() {
157         return mSingleDevice;
158     }
159 
160     /** @hide */
161     @NonNull
162     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getDeviceFilters()163     public List<DeviceFilter<?>> getDeviceFilters() {
164         return mDeviceFilters;
165     }
166 
167     /**
168      * A builder for {@link AssociationRequest}
169      */
170     public static final class Builder extends OneTimeUseBuilder<AssociationRequest> {
171         private boolean mSingleDevice = false;
172         @Nullable private ArrayList<DeviceFilter<?>> mDeviceFilters = null;
173         private @Nullable String mDeviceProfile = null;
174 
Builder()175         public Builder() {}
176 
177         /**
178          * Whether only a single device should match the provided filter.
179          *
180          * When scanning for a single device with a specifc {@link BluetoothDeviceFilter} mac
181          * address, bonded devices are also searched among. This allows to obtain the necessary app
182          * privileges even if the device is already paired.
183          *
184          * @param singleDevice if true, scanning for a device will stop as soon as at least one
185          *                     fitting device is found
186          */
187         @NonNull
setSingleDevice(boolean singleDevice)188         public Builder setSingleDevice(boolean singleDevice) {
189             checkNotUsed();
190             this.mSingleDevice = singleDevice;
191             return this;
192         }
193 
194         /**
195          * @param deviceFilter if set, only devices matching the given filter will be shown to the
196          *                     user
197          */
198         @NonNull
addDeviceFilter(@ullable DeviceFilter<?> deviceFilter)199         public Builder addDeviceFilter(@Nullable DeviceFilter<?> deviceFilter) {
200             checkNotUsed();
201             if (deviceFilter != null) {
202                 mDeviceFilters = ArrayUtils.add(mDeviceFilters, deviceFilter);
203             }
204             return this;
205         }
206 
207         /**
208          * If set, association will be requested as a corresponding kind of device
209          */
210         @NonNull
setDeviceProfile(@onNull @eviceProfile String deviceProfile)211         public Builder setDeviceProfile(@NonNull @DeviceProfile String deviceProfile) {
212             checkNotUsed();
213             mDeviceProfile = deviceProfile;
214             return this;
215         }
216 
217         /** @inheritDoc */
218         @NonNull
219         @Override
build()220         public AssociationRequest build() {
221             markUsed();
222             return new AssociationRequest(
223                     mSingleDevice, emptyIfNull(mDeviceFilters),
224                     mDeviceProfile, null, null, -1L, false);
225         }
226     }
227 
228 
229 
230 
231 
232     // Code below generated by codegen v1.0.22.
233     //
234     // DO NOT MODIFY!
235     // CHECKSTYLE:OFF Generated code
236     //
237     // To regenerate run:
238     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/companion/AssociationRequest.java
239     //
240     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
241     //   Settings > Editor > Code Style > Formatter Control
242     //@formatter:off
243 
244 
245     /**
246      * Creates a new AssociationRequest.
247      *
248      * @param singleDevice
249      *   Whether only a single device should match the provided filter.
250      *
251      *   When scanning for a single device with a specifc {@link BluetoothDeviceFilter} mac
252      *   address, bonded devices are also searched among. This allows to obtain the necessary app
253      *   privileges even if the device is already paired.
254      * @param deviceFilters
255      *   If set, only devices matching either of the given filters will be shown to the user
256      * @param deviceProfile
257      *   If set, association will be requested as a corresponding kind of device
258      * @param callingPackage
259      *   The app package making the request.
260      *
261      *   Populated by the system.
262      * @param deviceProfilePrivilegesDescription
263      *   The user-readable description of the device profile's privileges.
264      *
265      *   Populated by the system.
266      * @param creationTime
267      *   The time at which his request was created
268      * @param skipPrompt
269      *   Whether the user-prompt may be skipped once the device is found.
270      *
271      *   Populated by the system.
272      * @hide
273      */
274     @DataClass.Generated.Member
AssociationRequest( boolean singleDevice, @NonNull List<DeviceFilter<?>> deviceFilters, @Nullable @DeviceProfile String deviceProfile, @Nullable String callingPackage, @Nullable String deviceProfilePrivilegesDescription, long creationTime, boolean skipPrompt)275     public AssociationRequest(
276             boolean singleDevice,
277             @NonNull List<DeviceFilter<?>> deviceFilters,
278             @Nullable @DeviceProfile String deviceProfile,
279             @Nullable String callingPackage,
280             @Nullable String deviceProfilePrivilegesDescription,
281             long creationTime,
282             boolean skipPrompt) {
283         this.mSingleDevice = singleDevice;
284         this.mDeviceFilters = deviceFilters;
285         com.android.internal.util.AnnotationValidations.validate(
286                 NonNull.class, null, mDeviceFilters);
287         this.mDeviceProfile = deviceProfile;
288         com.android.internal.util.AnnotationValidations.validate(
289                 DeviceProfile.class, null, mDeviceProfile);
290         this.mCallingPackage = callingPackage;
291         this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
292         this.mCreationTime = creationTime;
293         this.mSkipPrompt = skipPrompt;
294 
295         onConstructed();
296     }
297 
298     /**
299      * If set, association will be requested as a corresponding kind of device
300      *
301      * @hide
302      */
303     @DataClass.Generated.Member
getDeviceProfile()304     public @Nullable @DeviceProfile String getDeviceProfile() {
305         return mDeviceProfile;
306     }
307 
308     /**
309      * The app package making the request.
310      *
311      * Populated by the system.
312      *
313      * @hide
314      */
315     @DataClass.Generated.Member
getCallingPackage()316     public @Nullable String getCallingPackage() {
317         return mCallingPackage;
318     }
319 
320     /**
321      * The user-readable description of the device profile's privileges.
322      *
323      * Populated by the system.
324      *
325      * @hide
326      */
327     @DataClass.Generated.Member
getDeviceProfilePrivilegesDescription()328     public @Nullable String getDeviceProfilePrivilegesDescription() {
329         return mDeviceProfilePrivilegesDescription;
330     }
331 
332     /**
333      * The time at which his request was created
334      *
335      * @hide
336      */
337     @DataClass.Generated.Member
getCreationTime()338     public long getCreationTime() {
339         return mCreationTime;
340     }
341 
342     /**
343      * Whether the user-prompt may be skipped once the device is found.
344      *
345      * Populated by the system.
346      *
347      * @hide
348      */
349     @DataClass.Generated.Member
isSkipPrompt()350     public boolean isSkipPrompt() {
351         return mSkipPrompt;
352     }
353 
354     @Override
355     @DataClass.Generated.Member
toString()356     public String toString() {
357         // You can override field toString logic by defining methods like:
358         // String fieldNameToString() { ... }
359 
360         return "AssociationRequest { " +
361                 "singleDevice = " + mSingleDevice + ", " +
362                 "deviceFilters = " + mDeviceFilters + ", " +
363                 "deviceProfile = " + mDeviceProfile + ", " +
364                 "callingPackage = " + mCallingPackage + ", " +
365                 "deviceProfilePrivilegesDescription = " + mDeviceProfilePrivilegesDescription + ", " +
366                 "creationTime = " + mCreationTime + ", " +
367                 "skipPrompt = " + mSkipPrompt +
368         " }";
369     }
370 
371     @Override
372     @DataClass.Generated.Member
equals(@ullable Object o)373     public boolean equals(@Nullable Object o) {
374         // You can override field equality logic by defining either of the methods like:
375         // boolean fieldNameEquals(AssociationRequest other) { ... }
376         // boolean fieldNameEquals(FieldType otherValue) { ... }
377 
378         if (this == o) return true;
379         if (o == null || getClass() != o.getClass()) return false;
380         @SuppressWarnings("unchecked")
381         AssociationRequest that = (AssociationRequest) o;
382         //noinspection PointlessBooleanExpression
383         return true
384                 && mSingleDevice == that.mSingleDevice
385                 && Objects.equals(mDeviceFilters, that.mDeviceFilters)
386                 && Objects.equals(mDeviceProfile, that.mDeviceProfile)
387                 && Objects.equals(mCallingPackage, that.mCallingPackage)
388                 && Objects.equals(mDeviceProfilePrivilegesDescription, that.mDeviceProfilePrivilegesDescription)
389                 && mCreationTime == that.mCreationTime
390                 && mSkipPrompt == that.mSkipPrompt;
391     }
392 
393     @Override
394     @DataClass.Generated.Member
hashCode()395     public int hashCode() {
396         // You can override field hashCode logic by defining methods like:
397         // int fieldNameHashCode() { ... }
398 
399         int _hash = 1;
400         _hash = 31 * _hash + Boolean.hashCode(mSingleDevice);
401         _hash = 31 * _hash + Objects.hashCode(mDeviceFilters);
402         _hash = 31 * _hash + Objects.hashCode(mDeviceProfile);
403         _hash = 31 * _hash + Objects.hashCode(mCallingPackage);
404         _hash = 31 * _hash + Objects.hashCode(mDeviceProfilePrivilegesDescription);
405         _hash = 31 * _hash + Long.hashCode(mCreationTime);
406         _hash = 31 * _hash + Boolean.hashCode(mSkipPrompt);
407         return _hash;
408     }
409 
410     @Override
411     @DataClass.Generated.Member
writeToParcel(@onNull Parcel dest, int flags)412     public void writeToParcel(@NonNull Parcel dest, int flags) {
413         // You can override field parcelling by defining methods like:
414         // void parcelFieldName(Parcel dest, int flags) { ... }
415 
416         byte flg = 0;
417         if (mSingleDevice) flg |= 0x1;
418         if (mSkipPrompt) flg |= 0x40;
419         if (mDeviceProfile != null) flg |= 0x4;
420         if (mCallingPackage != null) flg |= 0x8;
421         if (mDeviceProfilePrivilegesDescription != null) flg |= 0x10;
422         dest.writeByte(flg);
423         dest.writeParcelableList(mDeviceFilters, flags);
424         if (mDeviceProfile != null) dest.writeString(mDeviceProfile);
425         if (mCallingPackage != null) dest.writeString(mCallingPackage);
426         if (mDeviceProfilePrivilegesDescription != null) dest.writeString(mDeviceProfilePrivilegesDescription);
427         dest.writeLong(mCreationTime);
428     }
429 
430     @Override
431     @DataClass.Generated.Member
describeContents()432     public int describeContents() { return 0; }
433 
434     /** @hide */
435     @SuppressWarnings({"unchecked", "RedundantCast"})
436     @DataClass.Generated.Member
AssociationRequest(@onNull Parcel in)437     /* package-private */ AssociationRequest(@NonNull Parcel in) {
438         // You can override field unparcelling by defining methods like:
439         // static FieldType unparcelFieldName(Parcel in) { ... }
440 
441         byte flg = in.readByte();
442         boolean singleDevice = (flg & 0x1) != 0;
443         boolean skipPrompt = (flg & 0x40) != 0;
444         List<DeviceFilter<?>> deviceFilters = new ArrayList<>();
445         in.readParcelableList(deviceFilters, DeviceFilter.class.getClassLoader());
446         String deviceProfile = (flg & 0x4) == 0 ? null : in.readString();
447         String callingPackage = (flg & 0x8) == 0 ? null : in.readString();
448         String deviceProfilePrivilegesDescription = (flg & 0x10) == 0 ? null : in.readString();
449         long creationTime = in.readLong();
450 
451         this.mSingleDevice = singleDevice;
452         this.mDeviceFilters = deviceFilters;
453         com.android.internal.util.AnnotationValidations.validate(
454                 NonNull.class, null, mDeviceFilters);
455         this.mDeviceProfile = deviceProfile;
456         com.android.internal.util.AnnotationValidations.validate(
457                 DeviceProfile.class, null, mDeviceProfile);
458         this.mCallingPackage = callingPackage;
459         this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
460         this.mCreationTime = creationTime;
461         this.mSkipPrompt = skipPrompt;
462 
463         onConstructed();
464     }
465 
466     @DataClass.Generated.Member
467     public static final @NonNull Parcelable.Creator<AssociationRequest> CREATOR
468             = new Parcelable.Creator<AssociationRequest>() {
469         @Override
470         public AssociationRequest[] newArray(int size) {
471             return new AssociationRequest[size];
472         }
473 
474         @Override
475         public AssociationRequest createFromParcel(@NonNull Parcel in) {
476             return new AssociationRequest(in);
477         }
478     };
479 
480     @DataClass.Generated(
481             time = 1615252862756L,
482             codegenVersion = "1.0.22",
483             sourceFile = "frameworks/base/core/java/android/companion/AssociationRequest.java",
484             inputSignatures = "private static final  java.lang.String LOG_TAG\npublic static final  java.lang.String DEVICE_PROFILE_WATCH\nprivate  boolean mSingleDevice\nprivate @com.android.internal.util.DataClass.PluralOf(\"deviceFilter\") @android.annotation.NonNull java.util.List<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String mDeviceProfile\nprivate @android.annotation.Nullable java.lang.String mCallingPackage\nprivate @android.annotation.Nullable java.lang.String mDeviceProfilePrivilegesDescription\nprivate  long mCreationTime\nprivate  boolean mSkipPrompt\nprivate  void onConstructed()\npublic  void setCallingPackage(java.lang.String)\npublic  void setDeviceProfilePrivilegesDescription(java.lang.String)\npublic  void setSkipPrompt(boolean)\npublic @android.compat.annotation.UnsupportedAppUsage boolean isSingleDevice()\npublic @android.annotation.NonNull @android.compat.annotation.UnsupportedAppUsage java.util.List<android.companion.DeviceFilter<?>> getDeviceFilters()\nclass AssociationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate  boolean mSingleDevice\nprivate @android.annotation.Nullable java.util.ArrayList<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable java.lang.String mDeviceProfile\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setSingleDevice(boolean)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder addDeviceFilter(android.companion.DeviceFilter<?>)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDeviceProfile(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override android.companion.AssociationRequest build()\nclass Builder extends android.provider.OneTimeUseBuilder<android.companion.AssociationRequest> implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true, genHiddenGetters=true, genParcelable=true, genHiddenConstructor=true, genBuilder=false)")
485     @Deprecated
__metadata()486     private void __metadata() {}
487 
488 
489     //@formatter:on
490     // End of generated code
491 
492 }
493