blob: 1de931eeb67587dad6a365d0516f651a00edd469 [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.patternFromString;
21import static android.companion.BluetoothDeviceFilterUtils.patternToString;
22
Eugene Susla36e866b2017-02-23 18:24:39 -080023import static com.android.internal.util.Preconditions.checkArgument;
Eugene Susla75fb8212017-04-05 10:36:24 -070024import static com.android.internal.util.Preconditions.checkState;
Eugene Susla36e866b2017-02-23 18:24:39 -080025
Eugene Susla6ed45d82017-01-22 13:52:51 -080026import 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.bluetooth.le.ScanFilter;
Eugene Susla36e866b2017-02-23 18:24:39 -080031import android.bluetooth.le.ScanRecord;
32import android.bluetooth.le.ScanResult;
Eugene Susla6ed45d82017-01-22 13:52:51 -080033import android.os.Parcel;
34import android.provider.OneTimeUseBuilder;
Eugene Susla36e866b2017-02-23 18:24:39 -080035import android.text.TextUtils;
Eugene Susla3c9aa172017-03-28 15:04:12 -070036import android.util.Log;
Eugene Susla6ed45d82017-01-22 13:52:51 -080037
Eugene Susla36e866b2017-02-23 18:24:39 -080038import com.android.internal.util.BitUtils;
Eugene Susla6ed45d82017-01-22 13:52:51 -080039import com.android.internal.util.ObjectUtils;
Eugene Susla36e866b2017-02-23 18:24:39 -080040import com.android.internal.util.Preconditions;
Eugene Susla6ed45d82017-01-22 13:52:51 -080041
Eugene Susla20bd9fc2017-04-27 14:34:59 -070042import java.nio.ByteOrder;
Eugene Suslaa38fbf62017-03-14 10:26:10 -070043import java.util.Arrays;
44import java.util.Objects;
Eugene Susla6ed45d82017-01-22 13:52:51 -080045import java.util.regex.Pattern;
46
47/**
48 * A filter for Bluetooth LE devices
49 *
50 * @see ScanFilter
51 */
Eugene Susla722463f2017-04-19 15:22:39 -070052public final class BluetoothLeDeviceFilter implements DeviceFilter<ScanResult> {
Eugene Susla6ed45d82017-01-22 13:52:51 -080053
Eugene Susla3c9aa172017-03-28 15:04:12 -070054 private static final boolean DEBUG = false;
Eugene Susla722463f2017-04-19 15:22:39 -070055 private static final String LOG_TAG = "BluetoothLeDeviceFilter";
Eugene Susla3c9aa172017-03-28 15:04:12 -070056
Eugene Susla36e866b2017-02-23 18:24:39 -080057 private static final int RENAME_PREFIX_LENGTH_LIMIT = 10;
Eugene Susla6ed45d82017-01-22 13:52:51 -080058
59 private final Pattern mNamePattern;
60 private final ScanFilter mScanFilter;
Eugene Susla36e866b2017-02-23 18:24:39 -080061 private final byte[] mRawDataFilter;
62 private final byte[] mRawDataFilterMask;
63 private final String mRenamePrefix;
64 private final String mRenameSuffix;
65 private final int mRenameBytesFrom;
Eugene Susla20bd9fc2017-04-27 14:34:59 -070066 private final int mRenameBytesLength;
Eugene Susla75fb8212017-04-05 10:36:24 -070067 private final int mRenameNameFrom;
Eugene Susla20bd9fc2017-04-27 14:34:59 -070068 private final int mRenameNameLength;
Eugene Susla36e866b2017-02-23 18:24:39 -080069 private final boolean mRenameBytesReverseOrder;
Eugene Susla6ed45d82017-01-22 13:52:51 -080070
Eugene Susla722463f2017-04-19 15:22:39 -070071 private BluetoothLeDeviceFilter(Pattern namePattern, ScanFilter scanFilter,
Eugene Susla36e866b2017-02-23 18:24:39 -080072 byte[] rawDataFilter, byte[] rawDataFilterMask, String renamePrefix,
Eugene Susla20bd9fc2017-04-27 14:34:59 -070073 String renameSuffix, int renameBytesFrom, int renameBytesLength,
74 int renameNameFrom, int renameNameLength, boolean renameBytesReverseOrder) {
Eugene Susla6ed45d82017-01-22 13:52:51 -080075 mNamePattern = namePattern;
76 mScanFilter = ObjectUtils.firstNotNull(scanFilter, ScanFilter.EMPTY);
Eugene Susla36e866b2017-02-23 18:24:39 -080077 mRawDataFilter = rawDataFilter;
78 mRawDataFilterMask = rawDataFilterMask;
79 mRenamePrefix = renamePrefix;
80 mRenameSuffix = renameSuffix;
81 mRenameBytesFrom = renameBytesFrom;
Eugene Susla20bd9fc2017-04-27 14:34:59 -070082 mRenameBytesLength = renameBytesLength;
Eugene Susla75fb8212017-04-05 10:36:24 -070083 mRenameNameFrom = renameNameFrom;
Eugene Susla20bd9fc2017-04-27 14:34:59 -070084 mRenameNameLength = renameNameLength;
Eugene Susla36e866b2017-02-23 18:24:39 -080085 mRenameBytesReverseOrder = renameBytesReverseOrder;
Eugene Susla6ed45d82017-01-22 13:52:51 -080086 }
87
88 /** @hide */
89 @Nullable
90 public Pattern getNamePattern() {
91 return mNamePattern;
92 }
93
94 /** @hide */
95 @NonNull
Mathew Inwood70e89d52018-08-09 15:27:52 +010096 @UnsupportedAppUsage
Eugene Susla6ed45d82017-01-22 13:52:51 -080097 public ScanFilter getScanFilter() {
98 return mScanFilter;
99 }
100
101 /** @hide */
Eugene Susla36e866b2017-02-23 18:24:39 -0800102 @Nullable
103 public byte[] getRawDataFilter() {
104 return mRawDataFilter;
105 }
106
107 /** @hide */
108 @Nullable
109 public byte[] getRawDataFilterMask() {
110 return mRawDataFilterMask;
111 }
112
113 /** @hide */
114 @Nullable
115 public String getRenamePrefix() {
116 return mRenamePrefix;
117 }
118
119 /** @hide */
120 @Nullable
121 public String getRenameSuffix() {
122 return mRenameSuffix;
123 }
124
125 /** @hide */
126 public int getRenameBytesFrom() {
127 return mRenameBytesFrom;
128 }
129
130 /** @hide */
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700131 public int getRenameBytesLength() {
132 return mRenameBytesLength;
Eugene Susla36e866b2017-02-23 18:24:39 -0800133 }
134
135 /** @hide */
136 public boolean isRenameBytesReverseOrder() {
137 return mRenameBytesReverseOrder;
138 }
139
140 /** @hide */
Eugene Susla6ed45d82017-01-22 13:52:51 -0800141 @Override
Eugene Susla36e866b2017-02-23 18:24:39 -0800142 @Nullable
143 public String getDeviceDisplayName(ScanResult sr) {
Eugene Susla75fb8212017-04-05 10:36:24 -0700144 if (mRenameBytesFrom < 0 && mRenameNameFrom < 0) {
145 return getDeviceDisplayNameInternal(sr.getDevice());
146 }
Eugene Susla36e866b2017-02-23 18:24:39 -0800147 final StringBuilder sb = new StringBuilder(TextUtils.emptyIfNull(mRenamePrefix));
Eugene Susla75fb8212017-04-05 10:36:24 -0700148 if (mRenameBytesFrom >= 0) {
149 final byte[] bytes = sr.getScanRecord().getBytes();
150 int startInclusive = mRenameBytesFrom;
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700151 int endInclusive = mRenameBytesFrom + mRenameBytesLength -1;
Eugene Susla75fb8212017-04-05 10:36:24 -0700152 int initial = mRenameBytesReverseOrder ? endInclusive : startInclusive;
153 int step = mRenameBytesReverseOrder ? -1 : 1;
154 for (int i = initial; startInclusive <= i && i <= endInclusive; i += step) {
155 sb.append(Byte.toHexString(bytes[i], true));
156 }
157 } else {
158 sb.append(
159 getDeviceDisplayNameInternal(sr.getDevice())
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700160 .substring(mRenameNameFrom, mRenameNameFrom + mRenameNameLength));
Eugene Susla36e866b2017-02-23 18:24:39 -0800161 }
162 return sb.append(TextUtils.emptyIfNull(mRenameSuffix)).toString();
163 }
164
165 /** @hide */
166 @Override
167 public boolean matches(ScanResult device) {
Eugene Susla3c9aa172017-03-28 15:04:12 -0700168 boolean result = matches(device.getDevice())
169 && (mRawDataFilter == null
170 || BitUtils.maskedEquals(device.getScanRecord().getBytes(),
171 mRawDataFilter, mRawDataFilterMask));
172 if (DEBUG) Log.i(LOG_TAG, "matches(this = " + this + ", device = " + device +
173 ") -> " + result);
174 return result;
Eugene Susla36e866b2017-02-23 18:24:39 -0800175 }
176
177 private boolean matches(BluetoothDevice device) {
Eugene Susla6ed45d82017-01-22 13:52:51 -0800178 return BluetoothDeviceFilterUtils.matches(getScanFilter(), device)
179 && BluetoothDeviceFilterUtils.matchesName(getNamePattern(), device);
180 }
181
Eugene Susla36e866b2017-02-23 18:24:39 -0800182 /** @hide */
183 @Override
184 public int getMediumType() {
185 return DeviceFilter.MEDIUM_TYPE_BLUETOOTH_LE;
186 }
187
Eugene Susla6ed45d82017-01-22 13:52:51 -0800188 @Override
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700189 public boolean equals(Object o) {
190 if (this == o) return true;
191 if (o == null || getClass() != o.getClass()) return false;
Eugene Susla722463f2017-04-19 15:22:39 -0700192 BluetoothLeDeviceFilter that = (BluetoothLeDeviceFilter) o;
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700193 return mRenameBytesFrom == that.mRenameBytesFrom &&
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700194 mRenameBytesLength == that.mRenameBytesLength &&
195 mRenameNameFrom == that.mRenameNameFrom &&
196 mRenameNameLength == that.mRenameNameLength &&
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700197 mRenameBytesReverseOrder == that.mRenameBytesReverseOrder &&
198 Objects.equals(mNamePattern, that.mNamePattern) &&
199 Objects.equals(mScanFilter, that.mScanFilter) &&
200 Arrays.equals(mRawDataFilter, that.mRawDataFilter) &&
201 Arrays.equals(mRawDataFilterMask, that.mRawDataFilterMask) &&
202 Objects.equals(mRenamePrefix, that.mRenamePrefix) &&
203 Objects.equals(mRenameSuffix, that.mRenameSuffix);
204 }
205
206 @Override
207 public int hashCode() {
208 return Objects.hash(mNamePattern, mScanFilter, mRawDataFilter, mRawDataFilterMask,
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700209 mRenamePrefix, mRenameSuffix, mRenameBytesFrom, mRenameBytesLength,
210 mRenameNameFrom, mRenameNameLength, mRenameBytesReverseOrder);
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700211 }
212
213 @Override
Eugene Susla6ed45d82017-01-22 13:52:51 -0800214 public void writeToParcel(Parcel dest, int flags) {
215 dest.writeString(patternToString(getNamePattern()));
216 dest.writeParcelable(mScanFilter, flags);
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700217 dest.writeByteArray(mRawDataFilter);
218 dest.writeByteArray(mRawDataFilterMask);
219 dest.writeString(mRenamePrefix);
220 dest.writeString(mRenameSuffix);
221 dest.writeInt(mRenameBytesFrom);
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700222 dest.writeInt(mRenameBytesLength);
Eugene Susla75fb8212017-04-05 10:36:24 -0700223 dest.writeInt(mRenameNameFrom);
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700224 dest.writeInt(mRenameNameLength);
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700225 dest.writeBoolean(mRenameBytesReverseOrder);
Eugene Susla6ed45d82017-01-22 13:52:51 -0800226 }
227
228 @Override
229 public int describeContents() {
230 return 0;
231 }
232
Eugene Suslaa7717e32017-04-17 19:13:31 -0700233 @Override
234 public String toString() {
235 return "BluetoothLEDeviceFilter{" +
236 "mNamePattern=" + mNamePattern +
237 ", mScanFilter=" + mScanFilter +
238 ", mRawDataFilter=" + Arrays.toString(mRawDataFilter) +
239 ", mRawDataFilterMask=" + Arrays.toString(mRawDataFilterMask) +
240 ", mRenamePrefix='" + mRenamePrefix + '\'' +
241 ", mRenameSuffix='" + mRenameSuffix + '\'' +
242 ", mRenameBytesFrom=" + mRenameBytesFrom +
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700243 ", mRenameBytesLength=" + mRenameBytesLength +
Eugene Suslaa7717e32017-04-17 19:13:31 -0700244 ", mRenameNameFrom=" + mRenameNameFrom +
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700245 ", mRenameNameLength=" + mRenameNameLength +
Eugene Suslaa7717e32017-04-17 19:13:31 -0700246 ", mRenameBytesReverseOrder=" + mRenameBytesReverseOrder +
247 '}';
248 }
249
Eugene Susla722463f2017-04-19 15:22:39 -0700250 public static final Creator<BluetoothLeDeviceFilter> CREATOR
251 = new Creator<BluetoothLeDeviceFilter>() {
Eugene Susla6ed45d82017-01-22 13:52:51 -0800252 @Override
Eugene Susla722463f2017-04-19 15:22:39 -0700253 public BluetoothLeDeviceFilter createFromParcel(Parcel in) {
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700254 Builder builder = new Builder()
Eugene Susla36e866b2017-02-23 18:24:39 -0800255 .setNamePattern(patternFromString(in.readString()))
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700256 .setScanFilter(in.readParcelable(null));
257 byte[] rawDataFilter = in.createByteArray();
258 byte[] rawDataFilterMask = in.createByteArray();
259 if (rawDataFilter != null) {
260 builder.setRawDataFilter(rawDataFilter, rawDataFilterMask);
261 }
262 String renamePrefix = in.readString();
263 String suffix = in.readString();
264 int bytesFrom = in.readInt();
265 int bytesTo = in.readInt();
Eugene Susla75fb8212017-04-05 10:36:24 -0700266 int nameFrom = in.readInt();
267 int nameTo = in.readInt();
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700268 boolean bytesReverseOrder = in.readBoolean();
269 if (renamePrefix != null) {
Eugene Susla75fb8212017-04-05 10:36:24 -0700270 if (bytesFrom >= 0) {
271 builder.setRenameFromBytes(renamePrefix, suffix, bytesFrom, bytesTo,
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700272 bytesReverseOrder ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
Eugene Susla75fb8212017-04-05 10:36:24 -0700273 } else {
274 builder.setRenameFromName(renamePrefix, suffix, nameFrom, nameTo);
275 }
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700276 }
277 return builder.build();
Eugene Susla6ed45d82017-01-22 13:52:51 -0800278 }
279
280 @Override
Eugene Susla722463f2017-04-19 15:22:39 -0700281 public BluetoothLeDeviceFilter[] newArray(int size) {
282 return new BluetoothLeDeviceFilter[size];
Eugene Susla6ed45d82017-01-22 13:52:51 -0800283 }
284 };
285
Eugene Susla36e866b2017-02-23 18:24:39 -0800286 public static int getRenamePrefixLengthLimit() {
287 return RENAME_PREFIX_LENGTH_LIMIT;
288 }
289
Eugene Susla6ed45d82017-01-22 13:52:51 -0800290 /**
Eugene Susla722463f2017-04-19 15:22:39 -0700291 * Builder for {@link BluetoothLeDeviceFilter}
Eugene Susla6ed45d82017-01-22 13:52:51 -0800292 */
Eugene Susla722463f2017-04-19 15:22:39 -0700293 public static final class Builder extends OneTimeUseBuilder<BluetoothLeDeviceFilter> {
Eugene Susla6ed45d82017-01-22 13:52:51 -0800294 private ScanFilter mScanFilter;
295 private Pattern mNamePattern;
Eugene Susla36e866b2017-02-23 18:24:39 -0800296 private byte[] mRawDataFilter;
297 private byte[] mRawDataFilterMask;
298 private String mRenamePrefix;
299 private String mRenameSuffix;
300 private int mRenameBytesFrom = -1;
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700301 private int mRenameBytesLength;
Eugene Susla75fb8212017-04-05 10:36:24 -0700302 private int mRenameNameFrom = -1;
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700303 private int mRenameNameLength;
Eugene Susla36e866b2017-02-23 18:24:39 -0800304 private boolean mRenameBytesReverseOrder = false;
Eugene Susla6ed45d82017-01-22 13:52:51 -0800305
306 /**
307 * @param regex if set, only devices with {@link BluetoothDevice#getName name} matching the
308 * given regular expression will be shown
Eugene Susla36e866b2017-02-23 18:24:39 -0800309 * @return self for chaining
Eugene Susla6ed45d82017-01-22 13:52:51 -0800310 */
311 public Builder setNamePattern(@Nullable Pattern regex) {
312 checkNotUsed();
313 mNamePattern = regex;
314 return this;
315 }
316
317 /**
318 * @param scanFilter a {@link ScanFilter} to filter devices by
319 *
Eugene Susla36e866b2017-02-23 18:24:39 -0800320 * @return self for chaining
Eugene Susla6ed45d82017-01-22 13:52:51 -0800321 * @see ScanFilter for specific details on its various fields
322 */
323 @NonNull
324 public Builder setScanFilter(@Nullable ScanFilter scanFilter) {
325 checkNotUsed();
326 mScanFilter = scanFilter;
327 return this;
328 }
329
Eugene Susla36e866b2017-02-23 18:24:39 -0800330 /**
331 * Filter devices by raw advertisement data, as obtained by {@link ScanRecord#getBytes}
332 *
333 * @param rawDataFilter bit values that have to match against advertized data
334 * @param rawDataFilterMask bits that have to be matched
335 * @return self for chaining
336 */
337 @NonNull
338 public Builder setRawDataFilter(@NonNull byte[] rawDataFilter,
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700339 @Nullable byte[] rawDataFilterMask) {
Eugene Susla36e866b2017-02-23 18:24:39 -0800340 checkNotUsed();
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700341 Preconditions.checkNotNull(rawDataFilter);
342 checkArgument(rawDataFilterMask == null ||
343 rawDataFilter.length == rawDataFilterMask.length,
Eugene Susla36e866b2017-02-23 18:24:39 -0800344 "Mask and filter should be the same length");
Eugene Suslaa38fbf62017-03-14 10:26:10 -0700345 mRawDataFilter = rawDataFilter;
346 mRawDataFilterMask = rawDataFilterMask;
Eugene Susla36e866b2017-02-23 18:24:39 -0800347 return this;
348 }
349
350 /**
351 * Rename the devices shown in the list, using specific bytes from the raw advertisement
352 * data ({@link ScanRecord#getBytes}) in hexadecimal format, as well as a custom
353 * prefix/suffix around them
354 *
355 * Note that the prefix length is limited to {@link #getRenamePrefixLengthLimit} characters
356 * to ensure that there's enough space to display the byte data
357 *
358 * The range of bytes to be displayed cannot be empty
359 *
360 * @param prefix to be displayed before the byte data
361 * @param suffix to be displayed after the byte data
362 * @param bytesFrom the start byte index to be displayed (inclusive)
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700363 * @param bytesLength the number of bytes to be displayed from the given index
364 * @param byteOrder whether the given range of bytes is big endian (will be displayed
365 * in same order) or little endian (will be flipped before displaying)
Eugene Susla36e866b2017-02-23 18:24:39 -0800366 * @return self for chaining
367 */
368 @NonNull
Eugene Susla75fb8212017-04-05 10:36:24 -0700369 public Builder setRenameFromBytes(@NonNull String prefix, @NonNull String suffix,
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700370 int bytesFrom, int bytesLength, ByteOrder byteOrder) {
Eugene Susla75fb8212017-04-05 10:36:24 -0700371 checkRenameNotSet();
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700372 checkRangeNotEmpty(bytesLength);
Eugene Susla36e866b2017-02-23 18:24:39 -0800373 mRenameBytesFrom = bytesFrom;
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700374 mRenameBytesLength = bytesLength;
375 mRenameBytesReverseOrder = byteOrder == ByteOrder.LITTLE_ENDIAN;
Eugene Susla75fb8212017-04-05 10:36:24 -0700376 return setRename(prefix, suffix);
377 }
378
379 /**
380 * Rename the devices shown in the list, using specific characters from the advertised name,
381 * as well as a custom prefix/suffix around them
382 *
383 * Note that the prefix length is limited to {@link #getRenamePrefixLengthLimit} characters
384 * to ensure that there's enough space to display the byte data
385 *
386 * The range of name characters to be displayed cannot be empty
387 *
388 * @param prefix to be displayed before the byte data
389 * @param suffix to be displayed after the byte data
390 * @param nameFrom the start name character index to be displayed (inclusive)
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700391 * @param nameLength the number of characters to be displayed from the given index
Eugene Susla75fb8212017-04-05 10:36:24 -0700392 * @return self for chaining
393 */
394 @NonNull
395 public Builder setRenameFromName(@NonNull String prefix, @NonNull String suffix,
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700396 int nameFrom, int nameLength) {
Eugene Susla75fb8212017-04-05 10:36:24 -0700397 checkRenameNotSet();
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700398 checkRangeNotEmpty(nameLength);
Eugene Susla75fb8212017-04-05 10:36:24 -0700399 mRenameNameFrom = nameFrom;
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700400 mRenameNameLength = nameLength;
Eugene Susla75fb8212017-04-05 10:36:24 -0700401 mRenameBytesReverseOrder = false;
402 return setRename(prefix, suffix);
403 }
404
405 private void checkRenameNotSet() {
406 checkState(mRenamePrefix == null, "Renaming rule can only be set once");
407 }
408
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700409 private void checkRangeNotEmpty(int length) {
410 checkArgument(length > 0, "Range must be non-empty");
Eugene Susla75fb8212017-04-05 10:36:24 -0700411 }
412
413 @NonNull
414 private Builder setRename(@NonNull String prefix, @NonNull String suffix) {
415 checkNotUsed();
416 checkArgument(TextUtils.length(prefix) <= getRenamePrefixLengthLimit(),
417 "Prefix is too long");
418 mRenamePrefix = prefix;
419 mRenameSuffix = suffix;
Eugene Susla36e866b2017-02-23 18:24:39 -0800420 return this;
421 }
422
Eugene Susla6ed45d82017-01-22 13:52:51 -0800423 /** @inheritDoc */
424 @Override
425 @NonNull
Eugene Susla722463f2017-04-19 15:22:39 -0700426 public BluetoothLeDeviceFilter build() {
Eugene Susla6ed45d82017-01-22 13:52:51 -0800427 markUsed();
Eugene Susla722463f2017-04-19 15:22:39 -0700428 return new BluetoothLeDeviceFilter(mNamePattern, mScanFilter,
Eugene Susla36e866b2017-02-23 18:24:39 -0800429 mRawDataFilter, mRawDataFilterMask,
430 mRenamePrefix, mRenameSuffix,
Eugene Susla20bd9fc2017-04-27 14:34:59 -0700431 mRenameBytesFrom, mRenameBytesLength,
432 mRenameNameFrom, mRenameNameLength,
Eugene Susla75fb8212017-04-05 10:36:24 -0700433 mRenameBytesReverseOrder);
Eugene Susla6ed45d82017-01-22 13:52:51 -0800434 }
435 }
436}