blob: 2649fbee4246a59f0f04961cabef62ef5c12c081 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.companion;
import static android.companion.BluetoothDeviceFilterUtils.getDeviceDisplayNameInternal;
import static android.companion.BluetoothDeviceFilterUtils.matchesAddress;
import static android.companion.BluetoothDeviceFilterUtils.matchesName;
import static android.companion.BluetoothDeviceFilterUtils.matchesServiceUuids;
import static android.companion.BluetoothDeviceFilterUtils.patternFromString;
import static android.companion.BluetoothDeviceFilterUtils.patternToString;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.ParcelUuid;
import android.provider.OneTimeUseBuilder;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
/**
* A filter for Bluetooth(non-LE) devices
*/
public final class BluetoothDeviceFilter implements DeviceFilter<BluetoothDevice> {
private final Pattern mNamePattern;
private final String mAddress;
private final List<ParcelUuid> mServiceUuids;
private final List<ParcelUuid> mServiceUuidMasks;
private BluetoothDeviceFilter(
Pattern namePattern,
String address,
List<ParcelUuid> serviceUuids,
List<ParcelUuid> serviceUuidMasks) {
mNamePattern = namePattern;
mAddress = address;
mServiceUuids = CollectionUtils.emptyIfNull(serviceUuids);
mServiceUuidMasks = CollectionUtils.emptyIfNull(serviceUuidMasks);
}
private BluetoothDeviceFilter(Parcel in) {
this(
patternFromString(in.readString()),
in.readString(),
readUuids(in),
readUuids(in));
}
private static List<ParcelUuid> readUuids(Parcel in) {
return in.readParcelableList(new ArrayList<>(), ParcelUuid.class.getClassLoader());
}
/** @hide */
@Override
public boolean matches(BluetoothDevice device) {
return matchesAddress(mAddress, device)
&& matchesServiceUuids(mServiceUuids, mServiceUuidMasks, device)
&& matchesName(getNamePattern(), device);
}
/** @hide */
@Override
public String getDeviceDisplayName(BluetoothDevice device) {
return getDeviceDisplayNameInternal(device);
}
/** @hide */
@Override
public int getMediumType() {
return DeviceFilter.MEDIUM_TYPE_BLUETOOTH;
}
/** @hide */
@Nullable
public Pattern getNamePattern() {
return mNamePattern;
}
/** @hide */
@Nullable
@UnsupportedAppUsage
public String getAddress() {
return mAddress;
}
/** @hide */
@NonNull
public List<ParcelUuid> getServiceUuids() {
return mServiceUuids;
}
/** @hide */
@NonNull
public List<ParcelUuid> getServiceUuidMasks() {
return mServiceUuidMasks;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(patternToString(getNamePattern()));
dest.writeString(mAddress);
dest.writeParcelableList(mServiceUuids, flags);
dest.writeParcelableList(mServiceUuidMasks, flags);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BluetoothDeviceFilter that = (BluetoothDeviceFilter) o;
return Objects.equals(mNamePattern, that.mNamePattern) &&
Objects.equals(mAddress, that.mAddress) &&
Objects.equals(mServiceUuids, that.mServiceUuids) &&
Objects.equals(mServiceUuidMasks, that.mServiceUuidMasks);
}
@Override
public int hashCode() {
return Objects.hash(mNamePattern, mAddress, mServiceUuids, mServiceUuidMasks);
}
@Override
public int describeContents() {
return 0;
}
public static final @android.annotation.NonNull Creator<BluetoothDeviceFilter> CREATOR
= new Creator<BluetoothDeviceFilter>() {
@Override
public BluetoothDeviceFilter createFromParcel(Parcel in) {
return new BluetoothDeviceFilter(in);
}
@Override
public BluetoothDeviceFilter[] newArray(int size) {
return new BluetoothDeviceFilter[size];
}
};
/**
* A builder for {@link BluetoothDeviceFilter}
*/
public static final class Builder extends OneTimeUseBuilder<BluetoothDeviceFilter> {
private Pattern mNamePattern;
private String mAddress;
private ArrayList<ParcelUuid> mServiceUuid;
private ArrayList<ParcelUuid> mServiceUuidMask;
/**
* @param regex if set, only devices with {@link BluetoothDevice#getName name} matching the
* given regular expression will be shown
*/
public Builder setNamePattern(@Nullable Pattern regex) {
checkNotUsed();
mNamePattern = regex;
return this;
}
/**
* @param address if set, only devices with MAC address exactly matching the given one will
* pass the filter
*/
@NonNull
public Builder setAddress(@Nullable String address) {
checkNotUsed();
mAddress = address;
return this;
}
/**
* Add filtering by certain bits of {@link BluetoothDevice#getUuids()}
*
* A device with any uuid matching the given bits is considered passing
*
* @param serviceUuid the values for the bits to match
* @param serviceUuidMask if provided, only those bits would have to match.
*/
@NonNull
public Builder addServiceUuid(
@Nullable ParcelUuid serviceUuid, @Nullable ParcelUuid serviceUuidMask) {
checkNotUsed();
mServiceUuid = ArrayUtils.add(mServiceUuid, serviceUuid);
mServiceUuidMask = ArrayUtils.add(mServiceUuidMask, serviceUuidMask);
return this;
}
/** @inheritDoc */
@Override
@NonNull
public BluetoothDeviceFilter build() {
markUsed();
return new BluetoothDeviceFilter(
mNamePattern, mAddress, mServiceUuid, mServiceUuidMask);
}
}
}