16ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla/*
26ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * Copyright (C) 2017 The Android Open Source Project
36ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla *
46ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * Licensed under the Apache License, Version 2.0 (the "License");
56ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * you may not use this file except in compliance with the License.
66ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * You may obtain a copy of the License at
76ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla *
86ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla *      http://www.apache.org/licenses/LICENSE-2.0
96ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla *
106ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * Unless required by applicable law or agreed to in writing, software
116ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * distributed under the License is distributed on an "AS IS" BASIS,
126ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * See the License for the specific language governing permissions and
146ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * limitations under the License.
156ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla */
166ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
176ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslapackage android.companion;
186ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
1936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Suslaimport static android.companion.BluetoothDeviceFilterUtils.getDeviceDisplayNameInternal;
206ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport static android.companion.BluetoothDeviceFilterUtils.patternFromString;
216ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport static android.companion.BluetoothDeviceFilterUtils.patternToString;
226ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
2336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Suslaimport static com.android.internal.util.Preconditions.checkArgument;
2475fb821029f789cf8f306dbd72805d1581214785Eugene Suslaimport static com.android.internal.util.Preconditions.checkState;
2536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
266ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport android.annotation.NonNull;
276ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport android.annotation.Nullable;
286ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport android.bluetooth.BluetoothDevice;
296ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport android.bluetooth.le.ScanFilter;
3036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Suslaimport android.bluetooth.le.ScanRecord;
3136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Suslaimport android.bluetooth.le.ScanResult;
326ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport android.os.Parcel;
336ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport android.provider.OneTimeUseBuilder;
3436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Suslaimport android.text.TextUtils;
353c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Suslaimport android.util.Log;
366ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
3736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Suslaimport com.android.internal.util.BitUtils;
386ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport com.android.internal.util.ObjectUtils;
3936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Suslaimport com.android.internal.util.Preconditions;
406ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
4120bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Suslaimport java.nio.ByteOrder;
42a38fbf63fd2a29884637a59387643c801ed4f663Eugene Suslaimport java.util.Arrays;
43a38fbf63fd2a29884637a59387643c801ed4f663Eugene Suslaimport java.util.Objects;
446ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Suslaimport java.util.regex.Pattern;
456ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
466ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla/**
476ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * A filter for Bluetooth LE devices
486ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla *
496ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla * @see ScanFilter
506ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla */
51722463ff953168ae27bedf61a586f296813fc9feEugene Suslapublic final class BluetoothLeDeviceFilter implements DeviceFilter<ScanResult> {
526ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
533c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Susla    private static final boolean DEBUG = false;
54722463ff953168ae27bedf61a586f296813fc9feEugene Susla    private static final String LOG_TAG = "BluetoothLeDeviceFilter";
553c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Susla
5636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    private static final int RENAME_PREFIX_LENGTH_LIMIT = 10;
576ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
586ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    private final Pattern mNamePattern;
596ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    private final ScanFilter mScanFilter;
6036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    private final byte[] mRawDataFilter;
6136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    private final byte[] mRawDataFilterMask;
6236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    private final String mRenamePrefix;
6336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    private final String mRenameSuffix;
6436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    private final int mRenameBytesFrom;
6520bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla    private final int mRenameBytesLength;
6675fb821029f789cf8f306dbd72805d1581214785Eugene Susla    private final int mRenameNameFrom;
6720bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla    private final int mRenameNameLength;
6836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    private final boolean mRenameBytesReverseOrder;
696ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
70722463ff953168ae27bedf61a586f296813fc9feEugene Susla    private BluetoothLeDeviceFilter(Pattern namePattern, ScanFilter scanFilter,
7136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla            byte[] rawDataFilter, byte[] rawDataFilterMask, String renamePrefix,
7220bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla            String renameSuffix, int renameBytesFrom, int renameBytesLength,
7320bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla            int renameNameFrom, int renameNameLength, boolean renameBytesReverseOrder) {
746ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        mNamePattern = namePattern;
756ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        mScanFilter = ObjectUtils.firstNotNull(scanFilter, ScanFilter.EMPTY);
7636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        mRawDataFilter = rawDataFilter;
7736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        mRawDataFilterMask = rawDataFilterMask;
7836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        mRenamePrefix = renamePrefix;
7936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        mRenameSuffix = renameSuffix;
8036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        mRenameBytesFrom = renameBytesFrom;
8120bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla        mRenameBytesLength = renameBytesLength;
8275fb821029f789cf8f306dbd72805d1581214785Eugene Susla        mRenameNameFrom = renameNameFrom;
8320bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla        mRenameNameLength = renameNameLength;
8436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        mRenameBytesReverseOrder = renameBytesReverseOrder;
856ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    }
866ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
8736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    /** @hide */
8836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    @Nullable
8936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public Pattern getNamePattern() {
9036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return mNamePattern;
916ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    }
926ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
936ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    /** @hide */
946ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    @NonNull
9536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public ScanFilter getScanFilter() {
9636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return mScanFilter;
976ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    }
986ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
996ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    /** @hide */
10036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    @Nullable
10136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public byte[] getRawDataFilter() {
10236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return mRawDataFilter;
103e70e6aa62c6f3a9a79624a4f9d97df95edda0364Eugene Susla    }
104e70e6aa62c6f3a9a79624a4f9d97df95edda0364Eugene Susla
105e70e6aa62c6f3a9a79624a4f9d97df95edda0364Eugene Susla    /** @hide */
106e70e6aa62c6f3a9a79624a4f9d97df95edda0364Eugene Susla    @Nullable
10736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public byte[] getRawDataFilterMask() {
10836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return mRawDataFilterMask;
109e70e6aa62c6f3a9a79624a4f9d97df95edda0364Eugene Susla    }
110e70e6aa62c6f3a9a79624a4f9d97df95edda0364Eugene Susla
111e70e6aa62c6f3a9a79624a4f9d97df95edda0364Eugene Susla    /** @hide */
11236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    @Nullable
11336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public String getRenamePrefix() {
11436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return mRenamePrefix;
11536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    }
11636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
11736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    /** @hide */
11836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    @Nullable
11936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public String getRenameSuffix() {
12036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return mRenameSuffix;
12136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    }
12236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
12336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    /** @hide */
12436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public int getRenameBytesFrom() {
12536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return mRenameBytesFrom;
12636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    }
12736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
12836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    /** @hide */
12920bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla    public int getRenameBytesLength() {
13020bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla        return mRenameBytesLength;
13136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    }
13236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
13336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    /** @hide */
13436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public boolean isRenameBytesReverseOrder() {
13536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return mRenameBytesReverseOrder;
13636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    }
13736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
13836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    /** @hide */
13936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    @Override
14036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    @Nullable
14136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public String getDeviceDisplayName(ScanResult sr) {
14275fb821029f789cf8f306dbd72805d1581214785Eugene Susla        if (mRenameBytesFrom < 0 && mRenameNameFrom < 0) {
14375fb821029f789cf8f306dbd72805d1581214785Eugene Susla            return getDeviceDisplayNameInternal(sr.getDevice());
14475fb821029f789cf8f306dbd72805d1581214785Eugene Susla        }
14536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        final StringBuilder sb = new StringBuilder(TextUtils.emptyIfNull(mRenamePrefix));
14675fb821029f789cf8f306dbd72805d1581214785Eugene Susla        if (mRenameBytesFrom >= 0) {
14775fb821029f789cf8f306dbd72805d1581214785Eugene Susla            final byte[] bytes = sr.getScanRecord().getBytes();
14875fb821029f789cf8f306dbd72805d1581214785Eugene Susla            int startInclusive = mRenameBytesFrom;
14920bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla            int endInclusive = mRenameBytesFrom + mRenameBytesLength -1;
15075fb821029f789cf8f306dbd72805d1581214785Eugene Susla            int initial = mRenameBytesReverseOrder ? endInclusive : startInclusive;
15175fb821029f789cf8f306dbd72805d1581214785Eugene Susla            int step = mRenameBytesReverseOrder ? -1 : 1;
15275fb821029f789cf8f306dbd72805d1581214785Eugene Susla            for (int i = initial; startInclusive <= i && i <= endInclusive; i += step) {
15375fb821029f789cf8f306dbd72805d1581214785Eugene Susla                sb.append(Byte.toHexString(bytes[i], true));
15475fb821029f789cf8f306dbd72805d1581214785Eugene Susla            }
15575fb821029f789cf8f306dbd72805d1581214785Eugene Susla        } else {
15675fb821029f789cf8f306dbd72805d1581214785Eugene Susla            sb.append(
15775fb821029f789cf8f306dbd72805d1581214785Eugene Susla                    getDeviceDisplayNameInternal(sr.getDevice())
15820bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                            .substring(mRenameNameFrom, mRenameNameFrom + mRenameNameLength));
15936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        }
16036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return sb.append(TextUtils.emptyIfNull(mRenameSuffix)).toString();
1616ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    }
1626ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
1636ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    /** @hide */
1646ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    @Override
16536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public boolean matches(ScanResult device) {
1663c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Susla        boolean result = matches(device.getDevice())
1673c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Susla                && (mRawDataFilter == null
1683c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Susla                    || BitUtils.maskedEquals(device.getScanRecord().getBytes(),
1693c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Susla                            mRawDataFilter, mRawDataFilterMask));
1703c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Susla        if (DEBUG) Log.i(LOG_TAG, "matches(this = " + this + ", device = " + device +
1713c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Susla                ") -> " + result);
1723c9aa1767ca0ddc881f53c2ce7eb3135670efef3Eugene Susla        return result;
17336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    }
17436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
17536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    private boolean matches(BluetoothDevice device) {
1766ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        return BluetoothDeviceFilterUtils.matches(getScanFilter(), device)
1776ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla                && BluetoothDeviceFilterUtils.matchesName(getNamePattern(), device);
1786ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    }
1796ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
18036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    /** @hide */
18136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    @Override
18236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public int getMediumType() {
18336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return DeviceFilter.MEDIUM_TYPE_BLUETOOTH_LE;
18436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    }
18536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
1866ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    @Override
187a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla    public boolean equals(Object o) {
188a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        if (this == o) return true;
189a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        if (o == null || getClass() != o.getClass()) return false;
190722463ff953168ae27bedf61a586f296813fc9feEugene Susla        BluetoothLeDeviceFilter that = (BluetoothLeDeviceFilter) o;
191a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        return mRenameBytesFrom == that.mRenameBytesFrom &&
19220bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                mRenameBytesLength == that.mRenameBytesLength &&
19320bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                mRenameNameFrom == that.mRenameNameFrom &&
19420bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                mRenameNameLength == that.mRenameNameLength &&
195a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                mRenameBytesReverseOrder == that.mRenameBytesReverseOrder &&
196a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                Objects.equals(mNamePattern, that.mNamePattern) &&
197a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                Objects.equals(mScanFilter, that.mScanFilter) &&
198a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                Arrays.equals(mRawDataFilter, that.mRawDataFilter) &&
199a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                Arrays.equals(mRawDataFilterMask, that.mRawDataFilterMask) &&
200a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                Objects.equals(mRenamePrefix, that.mRenamePrefix) &&
201a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                Objects.equals(mRenameSuffix, that.mRenameSuffix);
202a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla    }
203a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla
204a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla    @Override
205a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla    public int hashCode() {
206a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        return Objects.hash(mNamePattern, mScanFilter, mRawDataFilter, mRawDataFilterMask,
20720bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                mRenamePrefix, mRenameSuffix, mRenameBytesFrom, mRenameBytesLength,
20820bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                mRenameNameFrom, mRenameNameLength, mRenameBytesReverseOrder);
209a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla    }
210a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla
211a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla    @Override
2126ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    public void writeToParcel(Parcel dest, int flags) {
2136ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        dest.writeString(patternToString(getNamePattern()));
2146ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        dest.writeParcelable(mScanFilter, flags);
215a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        dest.writeByteArray(mRawDataFilter);
216a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        dest.writeByteArray(mRawDataFilterMask);
217a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        dest.writeString(mRenamePrefix);
218a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        dest.writeString(mRenameSuffix);
219a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        dest.writeInt(mRenameBytesFrom);
22020bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla        dest.writeInt(mRenameBytesLength);
22175fb821029f789cf8f306dbd72805d1581214785Eugene Susla        dest.writeInt(mRenameNameFrom);
22220bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla        dest.writeInt(mRenameNameLength);
223a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla        dest.writeBoolean(mRenameBytesReverseOrder);
2246ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    }
2256ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
2266ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    @Override
2276ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    public int describeContents() {
2286ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        return 0;
2296ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    }
2306ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
231a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla    @Override
232a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla    public String toString() {
233a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla        return "BluetoothLEDeviceFilter{" +
234a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                "mNamePattern=" + mNamePattern +
235a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                ", mScanFilter=" + mScanFilter +
236a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                ", mRawDataFilter=" + Arrays.toString(mRawDataFilter) +
237a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                ", mRawDataFilterMask=" + Arrays.toString(mRawDataFilterMask) +
238a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                ", mRenamePrefix='" + mRenamePrefix + '\'' +
239a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                ", mRenameSuffix='" + mRenameSuffix + '\'' +
240a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                ", mRenameBytesFrom=" + mRenameBytesFrom +
24120bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                ", mRenameBytesLength=" + mRenameBytesLength +
242a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                ", mRenameNameFrom=" + mRenameNameFrom +
24320bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                ", mRenameNameLength=" + mRenameNameLength +
244a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                ", mRenameBytesReverseOrder=" + mRenameBytesReverseOrder +
245a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla                '}';
246a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla    }
247a7717e3072acad6cd6256ce3fdbb2bb94ecb06caEugene Susla
248722463ff953168ae27bedf61a586f296813fc9feEugene Susla    public static final Creator<BluetoothLeDeviceFilter> CREATOR
249722463ff953168ae27bedf61a586f296813fc9feEugene Susla            = new Creator<BluetoothLeDeviceFilter>() {
2506ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        @Override
251722463ff953168ae27bedf61a586f296813fc9feEugene Susla        public BluetoothLeDeviceFilter createFromParcel(Parcel in) {
252a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            Builder builder = new Builder()
25336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla                    .setNamePattern(patternFromString(in.readString()))
254a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                    .setScanFilter(in.readParcelable(null));
255a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            byte[] rawDataFilter = in.createByteArray();
256a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            byte[] rawDataFilterMask = in.createByteArray();
257a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            if (rawDataFilter != null) {
258a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                builder.setRawDataFilter(rawDataFilter, rawDataFilterMask);
259a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            }
260a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            String renamePrefix = in.readString();
261a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            String suffix = in.readString();
262a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            int bytesFrom = in.readInt();
263a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            int bytesTo = in.readInt();
26475fb821029f789cf8f306dbd72805d1581214785Eugene Susla            int nameFrom = in.readInt();
26575fb821029f789cf8f306dbd72805d1581214785Eugene Susla            int nameTo = in.readInt();
266a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            boolean bytesReverseOrder = in.readBoolean();
267a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            if (renamePrefix != null) {
26875fb821029f789cf8f306dbd72805d1581214785Eugene Susla                if (bytesFrom >= 0) {
26975fb821029f789cf8f306dbd72805d1581214785Eugene Susla                    builder.setRenameFromBytes(renamePrefix, suffix, bytesFrom, bytesTo,
27020bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                            bytesReverseOrder ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
27175fb821029f789cf8f306dbd72805d1581214785Eugene Susla                } else {
27275fb821029f789cf8f306dbd72805d1581214785Eugene Susla                    builder.setRenameFromName(renamePrefix, suffix, nameFrom, nameTo);
27375fb821029f789cf8f306dbd72805d1581214785Eugene Susla                }
274a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            }
275a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            return builder.build();
2766ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        }
2776ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
2786ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        @Override
279722463ff953168ae27bedf61a586f296813fc9feEugene Susla        public BluetoothLeDeviceFilter[] newArray(int size) {
280722463ff953168ae27bedf61a586f296813fc9feEugene Susla            return new BluetoothLeDeviceFilter[size];
2816ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        }
2826ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    };
2836ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
28436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    public static int getRenamePrefixLengthLimit() {
28536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        return RENAME_PREFIX_LENGTH_LIMIT;
28636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla    }
28736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
2886ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    /**
289722463ff953168ae27bedf61a586f296813fc9feEugene Susla     * Builder for {@link BluetoothLeDeviceFilter}
2906ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla     */
291722463ff953168ae27bedf61a586f296813fc9feEugene Susla    public static final class Builder extends OneTimeUseBuilder<BluetoothLeDeviceFilter> {
2926ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        private ScanFilter mScanFilter;
2936ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        private Pattern mNamePattern;
29436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        private byte[] mRawDataFilter;
29536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        private byte[] mRawDataFilterMask;
29636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        private String mRenamePrefix;
29736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        private String mRenameSuffix;
29836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        private int mRenameBytesFrom = -1;
29920bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla        private int mRenameBytesLength;
30075fb821029f789cf8f306dbd72805d1581214785Eugene Susla        private int mRenameNameFrom = -1;
30120bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla        private int mRenameNameLength;
30236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        private boolean mRenameBytesReverseOrder = false;
3036ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
3046ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        /**
3056ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla         * @param regex if set, only devices with {@link BluetoothDevice#getName name} matching the
3066ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla         *              given regular expression will be shown
30736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * @return self for chaining
3086ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla         */
3096ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        public Builder setNamePattern(@Nullable Pattern regex) {
3106ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla            checkNotUsed();
3116ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla            mNamePattern = regex;
3126ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla            return this;
3136ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        }
3146ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
3156ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        /**
3166ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla         * @param scanFilter a {@link ScanFilter} to filter devices by
3176ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla         *
31836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * @return self for chaining
3196ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla         * @see ScanFilter for specific details on its various fields
3206ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla         */
3216ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        @NonNull
3226ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        public Builder setScanFilter(@Nullable ScanFilter scanFilter) {
3236ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla            checkNotUsed();
3246ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla            mScanFilter = scanFilter;
3256ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla            return this;
3266ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        }
3276ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla
32836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        /**
32936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * Filter devices by raw advertisement data, as obtained by {@link ScanRecord#getBytes}
33036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         *
33136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * @param rawDataFilter bit values that have to match against advertized data
33236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * @param rawDataFilterMask bits that have to be matched
33336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * @return self for chaining
33436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         */
33536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        @NonNull
33636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        public Builder setRawDataFilter(@NonNull byte[] rawDataFilter,
337a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                @Nullable byte[] rawDataFilterMask) {
33836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla            checkNotUsed();
339a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            Preconditions.checkNotNull(rawDataFilter);
340a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            checkArgument(rawDataFilterMask == null ||
341a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla                    rawDataFilter.length == rawDataFilterMask.length,
34236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla                    "Mask and filter should be the same length");
343a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            mRawDataFilter = rawDataFilter;
344a38fbf63fd2a29884637a59387643c801ed4f663Eugene Susla            mRawDataFilterMask = rawDataFilterMask;
34536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla            return this;
34636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        }
34736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
34836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        /**
34936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * Rename the devices shown in the list, using specific bytes from the raw advertisement
35036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * data ({@link ScanRecord#getBytes}) in hexadecimal format, as well as a custom
35136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * prefix/suffix around them
35236e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         *
35336e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * Note that the prefix length is limited to {@link #getRenamePrefixLengthLimit} characters
35436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * to ensure that there's enough space to display the byte data
35536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         *
35636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * The range of bytes to be displayed cannot be empty
35736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         *
35836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * @param prefix to be displayed before the byte data
35936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * @param suffix to be displayed after the byte data
36036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * @param bytesFrom the start byte index to be displayed (inclusive)
36120bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla         * @param bytesLength the number of bytes to be displayed from the given index
36220bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla         * @param byteOrder whether the given range of bytes is big endian (will be displayed
36320bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla         *                   in same order) or little endian (will be flipped before displaying)
36436e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         * @return self for chaining
36536e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla         */
36636e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        @NonNull
36775fb821029f789cf8f306dbd72805d1581214785Eugene Susla        public Builder setRenameFromBytes(@NonNull String prefix, @NonNull String suffix,
36820bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                int bytesFrom, int bytesLength, ByteOrder byteOrder) {
36975fb821029f789cf8f306dbd72805d1581214785Eugene Susla            checkRenameNotSet();
37020bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla            checkRangeNotEmpty(bytesLength);
37136e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla            mRenameBytesFrom = bytesFrom;
37220bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla            mRenameBytesLength = bytesLength;
37320bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla            mRenameBytesReverseOrder = byteOrder == ByteOrder.LITTLE_ENDIAN;
37475fb821029f789cf8f306dbd72805d1581214785Eugene Susla            return setRename(prefix, suffix);
37575fb821029f789cf8f306dbd72805d1581214785Eugene Susla        }
37675fb821029f789cf8f306dbd72805d1581214785Eugene Susla
37775fb821029f789cf8f306dbd72805d1581214785Eugene Susla        /**
37875fb821029f789cf8f306dbd72805d1581214785Eugene Susla         * Rename the devices shown in the list, using specific characters from the advertised name,
37975fb821029f789cf8f306dbd72805d1581214785Eugene Susla         * as well as a custom prefix/suffix around them
38075fb821029f789cf8f306dbd72805d1581214785Eugene Susla         *
38175fb821029f789cf8f306dbd72805d1581214785Eugene Susla         * Note that the prefix length is limited to {@link #getRenamePrefixLengthLimit} characters
38275fb821029f789cf8f306dbd72805d1581214785Eugene Susla         * to ensure that there's enough space to display the byte data
38375fb821029f789cf8f306dbd72805d1581214785Eugene Susla         *
38475fb821029f789cf8f306dbd72805d1581214785Eugene Susla         * The range of name characters to be displayed cannot be empty
38575fb821029f789cf8f306dbd72805d1581214785Eugene Susla         *
38675fb821029f789cf8f306dbd72805d1581214785Eugene Susla         * @param prefix to be displayed before the byte data
38775fb821029f789cf8f306dbd72805d1581214785Eugene Susla         * @param suffix to be displayed after the byte data
38875fb821029f789cf8f306dbd72805d1581214785Eugene Susla         * @param nameFrom the start name character index to be displayed (inclusive)
38920bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla         * @param nameLength the number of characters to be displayed from the given index
39075fb821029f789cf8f306dbd72805d1581214785Eugene Susla         * @return self for chaining
39175fb821029f789cf8f306dbd72805d1581214785Eugene Susla         */
39275fb821029f789cf8f306dbd72805d1581214785Eugene Susla        @NonNull
39375fb821029f789cf8f306dbd72805d1581214785Eugene Susla        public Builder setRenameFromName(@NonNull String prefix, @NonNull String suffix,
39420bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                int nameFrom, int nameLength) {
39575fb821029f789cf8f306dbd72805d1581214785Eugene Susla            checkRenameNotSet();
39620bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla            checkRangeNotEmpty(nameLength);
39775fb821029f789cf8f306dbd72805d1581214785Eugene Susla            mRenameNameFrom = nameFrom;
39820bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla            mRenameNameLength = nameLength;
39975fb821029f789cf8f306dbd72805d1581214785Eugene Susla            mRenameBytesReverseOrder = false;
40075fb821029f789cf8f306dbd72805d1581214785Eugene Susla            return setRename(prefix, suffix);
40175fb821029f789cf8f306dbd72805d1581214785Eugene Susla        }
40275fb821029f789cf8f306dbd72805d1581214785Eugene Susla
40375fb821029f789cf8f306dbd72805d1581214785Eugene Susla        private void checkRenameNotSet() {
40475fb821029f789cf8f306dbd72805d1581214785Eugene Susla            checkState(mRenamePrefix == null, "Renaming rule can only be set once");
40575fb821029f789cf8f306dbd72805d1581214785Eugene Susla        }
40675fb821029f789cf8f306dbd72805d1581214785Eugene Susla
40720bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla        private void checkRangeNotEmpty(int length) {
40820bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla            checkArgument(length > 0, "Range must be non-empty");
40975fb821029f789cf8f306dbd72805d1581214785Eugene Susla        }
41075fb821029f789cf8f306dbd72805d1581214785Eugene Susla
41175fb821029f789cf8f306dbd72805d1581214785Eugene Susla        @NonNull
41275fb821029f789cf8f306dbd72805d1581214785Eugene Susla        private Builder setRename(@NonNull String prefix, @NonNull String suffix) {
41375fb821029f789cf8f306dbd72805d1581214785Eugene Susla            checkNotUsed();
41475fb821029f789cf8f306dbd72805d1581214785Eugene Susla            checkArgument(TextUtils.length(prefix) <= getRenamePrefixLengthLimit(),
41575fb821029f789cf8f306dbd72805d1581214785Eugene Susla                    "Prefix is too long");
41675fb821029f789cf8f306dbd72805d1581214785Eugene Susla            mRenamePrefix = prefix;
41775fb821029f789cf8f306dbd72805d1581214785Eugene Susla            mRenameSuffix = suffix;
41836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla            return this;
41936e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla        }
42036e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla
4216ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        /** @inheritDoc */
4226ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        @Override
4236ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        @NonNull
424722463ff953168ae27bedf61a586f296813fc9feEugene Susla        public BluetoothLeDeviceFilter build() {
4256ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla            markUsed();
426722463ff953168ae27bedf61a586f296813fc9feEugene Susla            return new BluetoothLeDeviceFilter(mNamePattern, mScanFilter,
42736e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla                    mRawDataFilter, mRawDataFilterMask,
42836e866b8e0ec08e45b5e7fbc65aeeb3a9bb7b11eEugene Susla                    mRenamePrefix, mRenameSuffix,
42920bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                    mRenameBytesFrom, mRenameBytesLength,
43020bd9fc81e32cafc86f3972b182b65ebdf5b1999Eugene Susla                    mRenameNameFrom, mRenameNameLength,
43175fb821029f789cf8f306dbd72805d1581214785Eugene Susla                    mRenameBytesReverseOrder);
4326ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla        }
4336ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla    }
4346ed45d8cd33c297e608aba94fc1f61dace7a7ccaEugene Susla}
435