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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UnsupportedAppUsage;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.provider.OneTimeUseBuilder;
25 
26 import com.android.internal.util.ArrayUtils;
27 import com.android.internal.util.CollectionUtils;
28 
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Objects;
32 
33 /**
34  * A request for the user to select a companion device to associate with.
35  *
36  * You can optionally set {@link Builder#addDeviceFilter filters} for which devices to show to the
37  * user to select from.
38  * The exact type and fields of the filter you can set depend on the
39  * medium type. See {@link Builder}'s static factory methods for specific protocols that are
40  * supported.
41  *
42  * You can also set {@link Builder#setSingleDevice single device} to request a popup with single
43  * device to be shown instead of a list to choose from
44  */
45 public final class AssociationRequest implements Parcelable {
46 
47     private final boolean mSingleDevice;
48     private final List<DeviceFilter<?>> mDeviceFilters;
49 
AssociationRequest( boolean singleDevice, @Nullable List<DeviceFilter<?>> deviceFilters)50     private AssociationRequest(
51             boolean singleDevice, @Nullable List<DeviceFilter<?>> deviceFilters) {
52         this.mSingleDevice = singleDevice;
53         this.mDeviceFilters = CollectionUtils.emptyIfNull(deviceFilters);
54     }
55 
AssociationRequest(Parcel in)56     private AssociationRequest(Parcel in) {
57         this(
58             in.readByte() != 0,
59             in.readParcelableList(new ArrayList<>(), AssociationRequest.class.getClassLoader()));
60     }
61 
62     /** @hide */
63     @UnsupportedAppUsage
isSingleDevice()64     public boolean isSingleDevice() {
65         return mSingleDevice;
66     }
67 
68     /** @hide */
69     @NonNull
70     @UnsupportedAppUsage
getDeviceFilters()71     public List<DeviceFilter<?>> getDeviceFilters() {
72         return mDeviceFilters;
73     }
74 
75     @Override
equals(Object o)76     public boolean equals(Object o) {
77         if (this == o) return true;
78         if (o == null || getClass() != o.getClass()) return false;
79         AssociationRequest that = (AssociationRequest) o;
80         return mSingleDevice == that.mSingleDevice &&
81                 Objects.equals(mDeviceFilters, that.mDeviceFilters);
82     }
83 
84     @Override
hashCode()85     public int hashCode() {
86         return Objects.hash(mSingleDevice, mDeviceFilters);
87     }
88 
89     @Override
toString()90     public String toString() {
91         return "AssociationRequest{" +
92                 "mSingleDevice=" + mSingleDevice +
93                 ", mDeviceFilters=" + mDeviceFilters +
94                 '}';
95     }
96 
97     @Override
writeToParcel(Parcel dest, int flags)98     public void writeToParcel(Parcel dest, int flags) {
99         dest.writeByte((byte) (mSingleDevice ? 1 : 0));
100         dest.writeParcelableList(mDeviceFilters, flags);
101     }
102 
103     @Override
describeContents()104     public int describeContents() {
105         return 0;
106     }
107 
108     public static final @android.annotation.NonNull Creator<AssociationRequest> CREATOR = new Creator<AssociationRequest>() {
109         @Override
110         public AssociationRequest createFromParcel(Parcel in) {
111             return new AssociationRequest(in);
112         }
113 
114         @Override
115         public AssociationRequest[] newArray(int size) {
116             return new AssociationRequest[size];
117         }
118     };
119 
120     /**
121      * A builder for {@link AssociationRequest}
122      */
123     public static final class Builder extends OneTimeUseBuilder<AssociationRequest> {
124         private boolean mSingleDevice = false;
125         @Nullable private ArrayList<DeviceFilter<?>> mDeviceFilters = null;
126 
Builder()127         public Builder() {}
128 
129         /**
130          * @param singleDevice if true, scanning for a device will stop as soon as at least one
131          *                     fitting device is found
132          */
133         @NonNull
setSingleDevice(boolean singleDevice)134         public Builder setSingleDevice(boolean singleDevice) {
135             checkNotUsed();
136             this.mSingleDevice = singleDevice;
137             return this;
138         }
139 
140         /**
141          * @param deviceFilter if set, only devices matching the given filter will be shown to the
142          *                     user
143          */
144         @NonNull
addDeviceFilter(@ullable DeviceFilter<?> deviceFilter)145         public Builder addDeviceFilter(@Nullable DeviceFilter<?> deviceFilter) {
146             checkNotUsed();
147             if (deviceFilter != null) {
148                 mDeviceFilters = ArrayUtils.add(mDeviceFilters, deviceFilter);
149             }
150             return this;
151         }
152 
153         /** @inheritDoc */
154         @NonNull
155         @Override
build()156         public AssociationRequest build() {
157             markUsed();
158             return new AssociationRequest(mSingleDevice, mDeviceFilters);
159         }
160     }
161 }
162