blob: fe0123c56e5712debeaf954d51f4465e8c73d2b9 [file] [log] [blame]
Eugene Susla6ed45d82017-01-22 13:52:51 -08001/*
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
17package android.companion;
18
Eugene Susla36e866b2017-02-23 18:24:39 -080019import static android.companion.BluetoothDeviceFilterUtils.getDeviceDisplayNameInternal;
Eugene Susla6ed45d82017-01-22 13:52:51 -080020import static android.companion.BluetoothDeviceFilterUtils.matchesAddress;
21import static android.companion.BluetoothDeviceFilterUtils.matchesName;
22import static android.companion.BluetoothDeviceFilterUtils.matchesServiceUuids;
23import static android.companion.BluetoothDeviceFilterUtils.patternFromString;
24import static android.companion.BluetoothDeviceFilterUtils.patternToString;
25
26import android.annotation.NonNull;
27import android.annotation.Nullable;
Mathew Inwood70e89d52018-08-09 15:27:52 +010028import android.annotation.UnsupportedAppUsage;
Eugene Susla6ed45d82017-01-22 13:52:51 -080029import android.bluetooth.BluetoothDevice;
30import android.os.Parcel;
31import android.os.ParcelUuid;
32import android.provider.OneTimeUseBuilder;
33
34import com.android.internal.util.ArrayUtils;
Eugene Susla6a7006a2017-03-13 12:57:58 -070035import com.android.internal.util.CollectionUtils;
Eugene Susla6ed45d82017-01-22 13:52:51 -080036
37import java.util.ArrayList;
38import java.util.List;
Eugene Suslaa38fbf62017-03-14 10:26:10 -070039import java.util.Objects;
Eugene Susla6ed45d82017-01-22 13:52:51 -080040import java.util.regex.Pattern;
41
42/**
43 * A filter for Bluetooth(non-LE) devices
44 */
45public final class BluetoothDeviceFilter implements DeviceFilter<BluetoothDevice> {
46
Eugene Susla6ed45d82017-01-22 13:52:51 -080047 private final Pattern mNamePattern;
48 private final String mAddress;
49 private final List<ParcelUuid> mServiceUuids;
50 private final List<ParcelUuid> mServiceUuidMasks;
51
52 private BluetoothDeviceFilter(
53 Pattern namePattern,
54 String address,
55 List<ParcelUuid> serviceUuids,
56 List<ParcelUuid> serviceUuidMasks) {
57 mNamePattern = namePattern;
58 mAddress = address;
Eugene Susla6a7006a2017-03-13 12:57:58 -070059 mServiceUuids = CollectionUtils.emptyIfNull(serviceUuids);
60 mServiceUuidMasks = CollectionUtils.emptyIfNull(serviceUuidMasks);
Eugene Susla6ed45d82017-01-22 13:52:51 -080061 }
62
63 private BluetoothDeviceFilter(Parcel in) {
64 this(
65 patternFromString(in.readString()),
66 in.readString(),
67 readUuids(in),
68 readUuids(in));
69 }
70
71 private static List<ParcelUuid> readUuids(Parcel in) {
Eugene Susla36e866b2017-02-23 18:24:39 -080072 return in.readParcelableList(new ArrayList<>(), ParcelUuid.class.getClassLoader());
Eugene Susla6ed45d82017-01-22 13:52:51 -080073 }
74
75 /** @hide */
76 @Override
77 public boolean matches(BluetoothDevice device) {
78 return matchesAddress(mAddress, device)
79 && matchesServiceUuids(mServiceUuids, mServiceUuidMasks, device)
80 && matchesName(getNamePattern(), device);
81 }
82
83 /** @hide */
Eugene Susla36e866b2017-02-23 18:24:39 -080084 @Override
85 public String getDeviceDisplayName(BluetoothDevice device) {
86 return getDeviceDisplayNameInternal(device);
87 }
88
89 /** @hide */
90 @Override
91 public int getMediumType() {
92 return DeviceFilter.MEDIUM_TYPE_BLUETOOTH;
93 }
94
95 /** @hide */
Eugene Susla6ed45d82017-01-22 13:52:51 -080096 @Nullable
97 public Pattern getNamePattern() {
98 return mNamePattern;
99 }
100
101 /** @hide */
102 @Nullable
Mathew Inwood70e89d52018-08-09 15:27:52 +0100103 @UnsupportedAppUsage
Eugene Susla6ed45d82017-01-22 13:52:51 -0800104 public String getAddress() {
105 return mAddress;
106 }
107
108 /** @hide */
109 @NonNull
110 public List<ParcelUuid> getServiceUuids() {
111 return mServiceUuids;
112 }
113
114 /** @hide */
115 @NonNull
116 public List<ParcelUuid> getServiceUuidMasks() {
117 return mServiceUuidMasks;
118 }
119
120 @Override
121 public void writeToParcel(Parcel dest, int flags) {
122 dest.writeString(patternToString(getNamePattern()));
123 dest.writeString(mAddress);
124 dest.writeParcelableList(mServiceUuids, flags);
125 dest.writeParcelableList(mServiceUuidMasks, flags);
126 }
127
128 @Override
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700129 public boolean equals(Object o) {
130 if (this == o) return true;
131 if (o == null || getClass() != o.getClass()) return false;
132 BluetoothDeviceFilter that = (BluetoothDeviceFilter) o;
133 return Objects.equals(mNamePattern, that.mNamePattern) &&
134 Objects.equals(mAddress, that.mAddress) &&
135 Objects.equals(mServiceUuids, that.mServiceUuids) &&
136 Objects.equals(mServiceUuidMasks, that.mServiceUuidMasks);
137 }
138
139 @Override
140 public int hashCode() {
141 return Objects.hash(mNamePattern, mAddress, mServiceUuids, mServiceUuidMasks);
142 }
143
144 @Override
Eugene Susla6ed45d82017-01-22 13:52:51 -0800145 public int describeContents() {
146 return 0;
147 }
148
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700149 public static final @android.annotation.NonNull Creator<BluetoothDeviceFilter> CREATOR
Eugene Susla6ed45d82017-01-22 13:52:51 -0800150 = new Creator<BluetoothDeviceFilter>() {
151 @Override
152 public BluetoothDeviceFilter createFromParcel(Parcel in) {
153 return new BluetoothDeviceFilter(in);
154 }
155
156 @Override
157 public BluetoothDeviceFilter[] newArray(int size) {
158 return new BluetoothDeviceFilter[size];
159 }
160 };
161
162 /**
163 * A builder for {@link BluetoothDeviceFilter}
164 */
165 public static final class Builder extends OneTimeUseBuilder<BluetoothDeviceFilter> {
166 private Pattern mNamePattern;
167 private String mAddress;
168 private ArrayList<ParcelUuid> mServiceUuid;
169 private ArrayList<ParcelUuid> mServiceUuidMask;
170
171 /**
172 * @param regex if set, only devices with {@link BluetoothDevice#getName name} matching the
173 * given regular expression will be shown
174 */
175 public Builder setNamePattern(@Nullable Pattern regex) {
176 checkNotUsed();
177 mNamePattern = regex;
178 return this;
179 }
180
181 /**
182 * @param address if set, only devices with MAC address exactly matching the given one will
183 * pass the filter
184 */
185 @NonNull
186 public Builder setAddress(@Nullable String address) {
187 checkNotUsed();
188 mAddress = address;
189 return this;
190 }
191
192 /**
193 * Add filtering by certain bits of {@link BluetoothDevice#getUuids()}
194 *
195 * A device with any uuid matching the given bits is considered passing
196 *
197 * @param serviceUuid the values for the bits to match
198 * @param serviceUuidMask if provided, only those bits would have to match.
199 */
200 @NonNull
201 public Builder addServiceUuid(
202 @Nullable ParcelUuid serviceUuid, @Nullable ParcelUuid serviceUuidMask) {
203 checkNotUsed();
204 mServiceUuid = ArrayUtils.add(mServiceUuid, serviceUuid);
205 mServiceUuidMask = ArrayUtils.add(mServiceUuidMask, serviceUuidMask);
206 return this;
207 }
208
209 /** @inheritDoc */
210 @Override
211 @NonNull
212 public BluetoothDeviceFilter build() {
213 markUsed();
214 return new BluetoothDeviceFilter(
215 mNamePattern, mAddress, mServiceUuid, mServiceUuidMask);
216 }
217 }
218}