Home | History | Annotate | Download | only in companion
      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