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