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