service: Add scan structures
Added the ScanFilter, ScanSettings, ScanResult structures that are
used in the BLE scan API.
Bug: 25744656
Change-Id: Id1bb28e7ebe85fd40013876aa097e1d0f0a4e471
diff --git a/service/Android.mk b/service/Android.mk
index 78c2dea..b00af1a 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -23,6 +23,9 @@
common/bluetooth/advertise_data.cpp \
common/bluetooth/advertise_settings.cpp \
common/bluetooth/gatt_identifier.cpp \
+ common/bluetooth/scan_filter.cpp \
+ common/bluetooth/scan_result.cpp \
+ common/bluetooth/scan_settings.cpp \
common/bluetooth/util/address_helper.cpp \
common/bluetooth/util/atomic_string.cpp \
common/bluetooth/uuid.cpp
diff --git a/service/common/bluetooth/binder/parcel_helpers.cpp b/service/common/bluetooth/binder/parcel_helpers.cpp
index d6d1cd9..141f940 100644
--- a/service/common/bluetooth/binder/parcel_helpers.cpp
+++ b/service/common/bluetooth/binder/parcel_helpers.cpp
@@ -16,10 +16,17 @@
#include "service/common/bluetooth/binder/parcel_helpers.h"
+#include "service/common/bluetooth/util/address_helper.h"
+
using android::Parcel;
using bluetooth::AdvertiseData;
using bluetooth::AdvertiseSettings;
+using bluetooth::GattIdentifier;
+using bluetooth::ScanFilter;
+using bluetooth::ScanResult;
+using bluetooth::ScanSettings;
+using bluetooth::UUID;
namespace ipc {
namespace binder {
@@ -85,13 +92,13 @@
new AdvertiseSettings(mode, timeout, tx_power, connectable));
}
-void WriteUUIDToParcel(const bluetooth::UUID& uuid, android::Parcel* parcel) {
+void WriteUUIDToParcel(const UUID& uuid, android::Parcel* parcel) {
// The scheme used by android.os.ParcelUuid is to wrote the most significant
// bits first as one 64-bit integer, followed by the least significant bits in
// a second 64-bit integer. This is the same as writing the raw-bytes in
// sequence, but we don't want to assume any host-endianness here. So follow
// the same scheme and use the same Parcel APIs.
- bluetooth::UUID::UUID128Bit bytes = uuid.GetFullBigEndian();
+ UUID::UUID128Bit bytes = uuid.GetFullBigEndian();
uint64_t most_sig_bits =
((((uint64_t) bytes[0]) << 56) |
@@ -117,9 +124,9 @@
parcel->writeUint64(least_sig_bits);
}
-std::unique_ptr<bluetooth::UUID> CreateUUIDFromParcel(
+std::unique_ptr<UUID> CreateUUIDFromParcel(
const android::Parcel& parcel) {
- bluetooth::UUID::UUID128Bit bytes;
+ UUID::UUID128Bit bytes;
uint64_t most_sig_bits = parcel.readUint64();
uint64_t least_sig_bits = parcel.readUint64();
@@ -142,11 +149,11 @@
bytes[14] = (least_sig_bits >> 8) & 0xFF;
bytes[15] = least_sig_bits & 0xFF;
- return std::unique_ptr<bluetooth::UUID>(new bluetooth::UUID(bytes));
+ return std::unique_ptr<UUID>(new UUID(bytes));
}
void WriteGattIdentifierToParcel(
- const bluetooth::GattIdentifier& gatt_id,
+ const GattIdentifier& gatt_id,
android::Parcel* parcel) {
parcel->writeCString(gatt_id.device_address().c_str());
parcel->writeInt32(gatt_id.is_primary());
@@ -160,7 +167,7 @@
parcel->writeInt32(gatt_id.descriptor_instance_id());
}
-std::unique_ptr<bluetooth::GattIdentifier> CreateGattIdentifierFromParcel(
+std::unique_ptr<GattIdentifier> CreateGattIdentifierFromParcel(
const android::Parcel& parcel) {
std::string device_address = parcel.readCString();
bool is_primary = parcel.readInt32();
@@ -173,12 +180,152 @@
int char_id = parcel.readInt32();
int desc_id = parcel.readInt32();
- return std::unique_ptr<bluetooth::GattIdentifier>(
- new bluetooth::GattIdentifier(
+ return std::unique_ptr<GattIdentifier>(
+ new GattIdentifier(
device_address, is_primary,
*service_uuid, *char_uuid, *desc_uuid,
service_id, char_id, desc_id));
}
+void WriteScanFilterToParcel(
+ const ScanFilter& filter,
+ android::Parcel* parcel) {
+ bool has_name = !filter.device_name().empty();
+ parcel->writeInt32(has_name ? 1 : 0);
+ if (has_name)
+ parcel->writeCString(filter.device_name().c_str());
+
+ bool has_address = !filter.device_address().empty();
+ parcel->writeInt32(has_address ? 1 : 0);
+ if (has_address)
+ parcel->writeCString(filter.device_address().c_str());
+
+ parcel->writeInt32(filter.service_uuid() ? 1 : 0);
+ if (filter.service_uuid()) {
+ WriteUUIDToParcel(*filter.service_uuid(), parcel);
+ parcel->writeInt32(filter.service_uuid_mask() ? 1 : 0);
+ if (filter.service_uuid_mask())
+ WriteUUIDToParcel(*filter.service_uuid_mask(), parcel);
+ }
+
+ // TODO(armansito): Support service and manufacturer data.
+}
+
+std::unique_ptr<ScanFilter> CreateScanFilterFromParcel(
+ const android::Parcel& parcel) {
+ std::string device_name;
+ if (parcel.readInt32() == 1)
+ device_name = parcel.readCString();
+
+ std::string device_address;
+ if (parcel.readInt32() == 1)
+ device_address = parcel.readCString();
+
+ std::unique_ptr<UUID> service_uuid, service_uuid_mask;
+ if (parcel.readInt32() == 1) {
+ service_uuid = CreateUUIDFromParcel(parcel);
+ if (parcel.readInt32() == 1)
+ service_uuid_mask = CreateUUIDFromParcel(parcel);
+ }
+
+ // TODO(armansito): Support service and manufacturer data.
+
+ std::unique_ptr<ScanFilter> filter(new ScanFilter());
+
+ filter->set_device_name(device_name);
+
+ if (!filter->SetDeviceAddress(device_address))
+ return nullptr;
+
+ if (!service_uuid)
+ return filter;
+
+ if (service_uuid_mask)
+ filter->SetServiceUuidWithMask(*service_uuid, *service_uuid_mask);
+ else
+ filter->SetServiceUuid(*service_uuid);
+
+ return filter;
+}
+
+void WriteScanSettingsToParcel(
+ const ScanSettings& settings,
+ android::Parcel* parcel) {
+ parcel->writeInt32(settings.mode());
+ parcel->writeInt32(settings.callback_type());
+ parcel->writeInt32(settings.result_type());
+ parcel->writeInt64(settings.report_delay().InMilliseconds());
+ parcel->writeInt32(settings.match_mode());
+ parcel->writeInt32(settings.match_count_per_filter());
+}
+
+std::unique_ptr<ScanSettings> CreateScanSettingsFromParcel(
+ const android::Parcel& parcel) {
+ ScanSettings::Mode mode =
+ static_cast<ScanSettings::Mode>(parcel.readInt32());
+ ScanSettings::CallbackType callback_type =
+ static_cast<ScanSettings::CallbackType>(parcel.readInt32());
+ ScanSettings::ResultType result_type =
+ static_cast<ScanSettings::ResultType>(parcel.readInt32());
+ base::TimeDelta report_delay = base::TimeDelta::FromMilliseconds(
+ parcel.readInt64());
+ ScanSettings::MatchMode match_mode =
+ static_cast<ScanSettings::MatchMode>(parcel.readInt32());
+ ScanSettings::MatchCount match_count_per_filter =
+ static_cast<ScanSettings::MatchCount>(parcel.readInt32());
+
+ return std::unique_ptr<ScanSettings>(new ScanSettings(
+ mode, callback_type, result_type, report_delay,
+ match_mode, match_count_per_filter));
+}
+
+void WriteScanResultToParcel(
+ const bluetooth::ScanResult& scan_result,
+ android::Parcel* parcel) {
+ // The Java framework code conditionally inserts 1 or 0 to indicate if the
+ // device adress and the scan record fields are present, based on whether the
+ // Java object is null. We do something similar here for consistency, although
+ // the native definition of ScanResult requires a valid BD_ADDR.
+ if (util::IsAddressValid(scan_result.device_address())) {
+ parcel->writeInt32(1);
+ parcel->writeCString(scan_result.device_address().c_str());
+ } else {
+ parcel->writeInt32(0);
+ }
+
+ if (!scan_result.scan_record().empty()) {
+ parcel->writeInt32(1);
+ parcel->writeByteArray(scan_result.scan_record().size(),
+ scan_result.scan_record().data());
+ } else {
+ parcel->writeInt32(0);
+ }
+
+ parcel->writeInt32(scan_result.rssi());
+}
+
+std::unique_ptr<bluetooth::ScanResult> CreateScanResultFromParcel(
+ const android::Parcel& parcel) {
+ std::string device_address;
+ if (parcel.readInt32())
+ device_address = parcel.readCString();
+
+ std::vector<uint8_t> scan_record;
+ if (parcel.readInt32()) {
+ int record_len = parcel.readInt32();
+ if (record_len != -1) {
+ uint8_t bytes[record_len];
+ parcel.read(bytes, record_len);
+
+ scan_record = std::vector<uint8_t>(bytes, bytes + record_len);
+ }
+ }
+
+ int rssi = parcel.readInt32();
+
+ return std::unique_ptr<ScanResult>(new ScanResult(
+ device_address, scan_record, rssi));
+}
+
} // namespace binder
} // namespace ipc
diff --git a/service/common/bluetooth/binder/parcel_helpers.h b/service/common/bluetooth/binder/parcel_helpers.h
index b96ea9b..a4c1073 100644
--- a/service/common/bluetooth/binder/parcel_helpers.h
+++ b/service/common/bluetooth/binder/parcel_helpers.h
@@ -23,11 +23,17 @@
#include <bluetooth/advertise_data.h>
#include <bluetooth/advertise_settings.h>
#include <bluetooth/gatt_identifier.h>
+#include <bluetooth/scan_filter.h>
+#include <bluetooth/scan_result.h>
+#include <bluetooth/scan_settings.h>
#include <bluetooth/uuid.h>
namespace ipc {
namespace binder {
+// Java Parcel meta-data constants.
+const int kParcelValList = 11;
+
// Helpers for converting bluetooth::AdvertiseData to/from Parcel
void WriteAdvertiseDataToParcel(
@@ -62,5 +68,32 @@
std::unique_ptr<bluetooth::GattIdentifier> CreateGattIdentifierFromParcel(
const android::Parcel& parcel);
+// Helpers for converting bluetooth::ScanFilter to/from Parcel
+
+void WriteScanFilterToParcel(
+ const bluetooth::ScanFilter& filter,
+ android::Parcel* parcel);
+
+std::unique_ptr<bluetooth::ScanFilter> CreateScanFilterFromParcel(
+ const android::Parcel& parcel);
+
+// Helpers for converting bluetooth::ScanSettings to/from Parcel
+
+void WriteScanSettingsToParcel(
+ const bluetooth::ScanSettings& settings,
+ android::Parcel* parcel);
+
+std::unique_ptr<bluetooth::ScanSettings> CreateScanSettingsFromParcel(
+ const android::Parcel& parcel);
+
+// Helpers for converting bluetooth::ScanResult to/from Parcel
+
+void WriteScanResultToParcel(
+ const bluetooth::ScanResult& scan_result,
+ android::Parcel* parcel);
+
+std::unique_ptr<bluetooth::ScanResult> CreateScanResultFromParcel(
+ const android::Parcel& parcel);
+
} // namespace binder
} // namespace ipc
diff --git a/service/common/bluetooth/scan_filter.cpp b/service/common/bluetooth/scan_filter.cpp
new file mode 100644
index 0000000..beeeedc
--- /dev/null
+++ b/service/common/bluetooth/scan_filter.cpp
@@ -0,0 +1,98 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// 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.
+//
+
+#include "service/common/bluetooth/scan_filter.h"
+
+#include "service/common/bluetooth/util/address_helper.h"
+
+namespace bluetooth {
+
+ScanFilter::ScanFilter(const ScanFilter& other) {
+ device_name_ = other.device_name_;
+ device_address_ = other.device_address_;
+
+ if (other.service_uuid_)
+ service_uuid_.reset(new UUID(*other.service_uuid_));
+
+ if (other.service_uuid_mask_)
+ service_uuid_mask_.reset(new UUID(*other.service_uuid_mask_));
+}
+
+ScanFilter& ScanFilter::operator=(const ScanFilter& other) {
+ device_name_ = other.device_name_;
+ device_address_ = other.device_address_;
+
+ if (other.service_uuid_)
+ service_uuid_.reset(new UUID(*other.service_uuid_));
+ else
+ service_uuid_ = nullptr;
+
+ if (other.service_uuid_mask_)
+ service_uuid_mask_.reset(new UUID(*other.service_uuid_mask_));
+ else
+ service_uuid_mask_ = nullptr;
+
+ return *this;
+}
+
+bool ScanFilter::SetDeviceAddress(const std::string& device_address) {
+ if (!util::IsAddressValid(device_address))
+ return false;
+
+ device_address_ = device_address;
+ return true;
+}
+
+void ScanFilter::SetServiceUuid(const UUID& service_uuid) {
+ service_uuid_.reset(new UUID(service_uuid));
+ service_uuid_mask_.reset();
+}
+
+void ScanFilter::SetServiceUuidWithMask(const UUID& service_uuid,
+ const UUID& mask) {
+ service_uuid_.reset(new UUID(service_uuid));
+ service_uuid_mask_.reset(new UUID(mask));
+}
+
+bool ScanFilter::operator==(const ScanFilter& rhs) const {
+ if (device_name_ != rhs.device_name_)
+ return false;
+
+ if (device_address_ != rhs.device_address_)
+ return false;
+
+ // Both must be either NULL or non-NULL. If only one of them is NULL, then
+ // return false.
+ if (!!service_uuid_ != !!rhs.service_uuid_)
+ return false;
+
+ if (service_uuid_ && rhs.service_uuid_ &&
+ *service_uuid_ != *rhs.service_uuid_)
+ return false;
+
+ // Both must be either NULL or non-NULL. If only one of them is NULL, then
+ // return false.
+ if (!!service_uuid_mask_ != !!rhs.service_uuid_mask_)
+ return false;
+
+ if (service_uuid_mask_ && rhs.service_uuid_mask_ &&
+ *service_uuid_mask_ != *rhs.service_uuid_mask_)
+ return false;
+
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/scan_filter.h b/service/common/bluetooth/scan_filter.h
new file mode 100644
index 0000000..5812b26
--- /dev/null
+++ b/service/common/bluetooth/scan_filter.h
@@ -0,0 +1,77 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// 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.
+//
+
+#pragma once
+
+#include <memory>
+
+#include <bluetooth/uuid.h>
+
+namespace bluetooth {
+
+// Used for filtering scan results by allowing clients to restrict scan results
+// to only those that are of interest to them.
+class ScanFilter {
+ public:
+ ScanFilter() = default;
+ ~ScanFilter() = default;
+
+ // Copy constructor and assignment operator.
+ ScanFilter(const ScanFilter& other);
+ ScanFilter& operator=(const ScanFilter& other);
+
+ // The device name used while filtering scan results.
+ const std::string& device_name() const { return device_name_; }
+ void set_device_name(const std::string& name) { device_name_ = name; }
+
+ // The device address used while filtering scan results. Address should be in
+ // the XX:XX:XX:XX:XX:XX where X is a hexadecimal digit.
+ const std::string& device_address() const { return device_address_; }
+
+ // Sets the device address used for filtering. Returns false if
+ // |device_address| is in an illegal format.
+ bool SetDeviceAddress(const std::string& device_address);
+
+ // The service UUID and its mask used while filtering scan results. See
+ // SetServiceUuidWithMask for what this mask does. The raw pointer returned
+ // from these getters belongs to the ScanFilter object. nullptr will be
+ // returned if these fields have not been set on this filter.
+ UUID* service_uuid() const { return service_uuid_.get(); }
+ UUID* service_uuid_mask() const { return service_uuid_mask_.get(); }
+
+ // Sets the service UUID for this filter.
+ void SetServiceUuid(const UUID& service_uuid);
+
+ // Sets the service UUID for this filter with a 128-bit mask. The mask allows
+ // the caller to partially filter scanned service UUIDs. For any of the
+ // 128-bits of a UUID, set the corresponding bit in the mask to 1 to match the
+ // advertised value, and 0 to ignore that bit.
+ void SetServiceUuidWithMask(const UUID& service_uuid, const UUID& mask);
+
+ // Comparison operator.
+ bool operator==(const ScanFilter& rhs) const;
+
+ private:
+ std::string device_name_;
+ std::string device_address_;
+
+ std::unique_ptr<UUID> service_uuid_;
+ std::unique_ptr<UUID> service_uuid_mask_;
+
+ // TODO(armansito): Add service and manufacturer data filter fields.
+};
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/scan_result.cpp b/service/common/bluetooth/scan_result.cpp
new file mode 100644
index 0000000..7656778
--- /dev/null
+++ b/service/common/bluetooth/scan_result.cpp
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// 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.
+//
+
+#include "service/common/bluetooth/scan_result.h"
+
+#include <base/logging.h>
+
+#include "service/common/bluetooth/util/address_helper.h"
+
+
+namespace bluetooth {
+
+ScanResult::ScanResult(const std::string& device_address,
+ const std::vector<uint8_t> scan_record,
+ int rssi)
+ : device_address_(device_address),
+ scan_record_(scan_record),
+ rssi_(rssi) {
+ CHECK(util::IsAddressValid(device_address)) << "Invalid BD_ADDR given: "
+ << device_address;
+}
+
+bool ScanResult::operator==(const ScanResult& rhs) const {
+ if (device_address_ != rhs.device_address_)
+ return false;
+
+ if (scan_record_ != rhs.scan_record_)
+ return false;
+
+ if (rssi_ != rhs.rssi_)
+ return false;
+
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/scan_result.h b/service/common/bluetooth/scan_result.h
new file mode 100644
index 0000000..f9fdbf3
--- /dev/null
+++ b/service/common/bluetooth/scan_result.h
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// 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.
+//
+
+#pragma once
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+namespace bluetooth {
+
+// ScanResult represents a single Bluetooth LE device scan result. It
+// encapsulates information about discovered LE devices.
+class ScanResult {
+ public:
+ ScanResult(const std::string& device_address,
+ const std::vector<uint8_t> scan_record,
+ int rssi);
+ ScanResult() = default;
+ ~ScanResult() = default;
+
+ // Returns the remote BD_ADDR associated with this scan result.
+ const std::string& device_address() const { return device_address_; }
+
+ // Returns the scan record (advertising +scan-response data) associated with
+ // this scan result.
+ const std::vector<uint8_t>& scan_record() const { return scan_record_; }
+
+ // Returns the RSSI associated with this scan result.
+ int rssi() const { return rssi_; }
+
+ // Comparison operator.
+ bool operator==(const ScanResult& rhs) const;
+
+ private:
+ std::string device_address_;
+ std::vector<uint8_t> scan_record_;
+ int rssi_;
+};
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/scan_settings.cpp b/service/common/bluetooth/scan_settings.cpp
new file mode 100644
index 0000000..2c807c0
--- /dev/null
+++ b/service/common/bluetooth/scan_settings.cpp
@@ -0,0 +1,65 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// 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.
+//
+
+#include "service/common/bluetooth/scan_settings.h"
+
+namespace bluetooth {
+
+ScanSettings::ScanSettings()
+ : mode_(MODE_LOW_POWER),
+ callback_type_(CALLBACK_TYPE_ALL_MATCHES),
+ result_type_(RESULT_TYPE_FULL),
+ match_count_per_filter_(MATCH_COUNT_MAX_ADVERTISEMENTS) {
+}
+
+ScanSettings::ScanSettings(
+ Mode mode,
+ CallbackTypeBitField callback_type,
+ ResultType result_type,
+ base::TimeDelta report_delay_ms,
+ MatchMode match_mode,
+ MatchCount match_count_per_filter)
+ : mode_(mode),
+ callback_type_(callback_type),
+ result_type_(result_type),
+ report_delay_ms_(report_delay_ms),
+ match_mode_(match_mode),
+ match_count_per_filter_(match_count_per_filter) {
+}
+
+bool ScanSettings::operator==(const ScanSettings& rhs) const {
+ if (mode_ != rhs.mode_)
+ return false;
+
+ if (callback_type_ != rhs.callback_type_)
+ return false;
+
+ if (result_type_ != rhs.result_type_)
+ return false;
+
+ if (report_delay_ms_ != rhs.report_delay_ms_)
+ return false;
+
+ if (match_mode_ != rhs.match_mode_)
+ return false;
+
+ if (match_count_per_filter_ != rhs.match_count_per_filter_)
+ return false;
+
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/scan_settings.h b/service/common/bluetooth/scan_settings.h
new file mode 100644
index 0000000..8f183b6
--- /dev/null
+++ b/service/common/bluetooth/scan_settings.h
@@ -0,0 +1,164 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// 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.
+//
+
+#pragma once
+
+#include <base/time/time.h>
+
+namespace bluetooth {
+
+// ScanSettings encapsulates Bluetooth LE device scan parameters. This is the
+// native equivalent of the Android framework class defined in
+// frameworks/base/core/java/android/bluetooth/le/ScanSettings.java.
+class ScanSettings {
+ public:
+ // A scan mode describes the power consumption involved in LE scans.
+ enum Mode {
+ // A special Bluetooth LE scan mode. Applications using this scan mode will
+ // passively listen for other scan results without starting BLE scans
+ // themselves.
+ MODE_OPPORTUNISTIC = -1,
+
+ // Perform Bluetooth LE scan in low power mode. This is the default scan
+ // mode as it consumes the least power.
+ MODE_LOW_POWER = 0,
+
+ // Perform Bluetooth LE scan in balanced power mode. Scan results are
+ // returned at a rate that provides a good trade-off between scan frequency
+ // and power consumption.
+ MODE_BALANCED = 1,
+
+ // Scan using the highest duty cycle. It's recommended to only use this mode
+ // when the application is running in the foreground.
+ MODE_LOW_LATENCY = 2,
+ };
+
+ // A callback type describes how scan results will be reported to applications
+ // in asynchronous callbacks.
+ enum CallbackType {
+ // Trigger a callback for every Bluetooth advertisement found that matches
+ // the filter criteria. If no filter is active, all advertisement packets
+ // are reported.
+ CALLBACK_TYPE_ALL_MATCHES = 1,
+
+ // A result callback is only triggered for the first advertisement packet
+ // received that matches the filter criteria. This requires that the
+ // hardware support the offloaded filtering feature.
+ CALLBACK_TYPE_FIRST_MATCH = 2,
+
+ // Receive a callback when advertisements are no longer received from a
+ // device that has been previously reported by a first match callback. This
+ // requires that the hardware support the offloaded filtering feature.
+ CALLBACK_TYPE_MATCH_LOST = 4,
+ };
+ using CallbackTypeBitField = int;
+
+ // Determines how many advertisements to match per filter.
+ enum MatchCount {
+ // Match one advertisement per filter.
+ MATCH_COUNT_ONE_ADVERTISEMENT = 1,
+
+ // Match few advertisements per filter depending on the current capability
+ // and availability of hardware resources.
+ MATCH_COUNT_FEW_ADVERTISEMENTS = 2,
+
+ // Match as many advertisements per filter as the underlying hardware can
+ // allow, depending on the current capability and availability of hardware
+ // resources.
+ MATCH_COUNT_MAX_ADVERTISEMENTS = 3,
+ };
+
+ // Hardware filter match mode.
+ enum MatchMode {
+ // In aggressive mode the hardware will determine a match sooner even with
+ // feeble signal strength and a low number of sightings in a duration.
+ MATCH_MODE_AGGRESSIVE = 1,
+
+ // In sticky mode a higher threshold of signal strength and sightings is
+ // required before a scan result is reported by the hardware.
+ MATCH_MODE_STICKY = 2,
+ };
+
+ // Scan result type describes the contents of each scan result.
+ enum ResultType {
+ // Request full scan results which contain the device name, RSSI,
+ // advertising data, scan response data, and the scan timestamp.
+ RESULT_TYPE_FULL = 0,
+
+ // Request abbreviated scan results which contain the device name, RSSI, and
+ // scan timestamp.
+ // Note: It is possible for an application to get more scan results than it
+ // asked for, if there are multiple apps using this type.
+ RESULT_TYPE_ABBREVIATED = 1,
+ };
+
+ // The default constructor sets all fields to defaults:
+ // mode: MODE_LOW_POWER
+ // callback_type: CALLBACK_TYPE_ALL_MATCHES
+ // result_type: RESULT_TYPE_FULL
+ // report_delay_ms: 0
+ // match_mode: MATCH_MODE_AGGRESSIVE
+ // match_count_per_filter: MATCH_COUNT_MAX_ADVERTISEMENTS
+ ScanSettings();
+ ScanSettings(Mode mode,
+ CallbackTypeBitField callback_type,
+ ResultType result_type,
+ base::TimeDelta report_delay_ms,
+ MatchMode match_mode,
+ MatchCount match_count_per_filter);
+ ~ScanSettings() = default;
+
+ // Returns the scan mode.
+ Mode mode() const { return mode_; }
+ void set_mode(Mode mode) { mode_ = mode; }
+
+ // Returns the callback type.
+ CallbackTypeBitField callback_type() const { return callback_type_; }
+ void set_callback_type(CallbackTypeBitField type) { callback_type_ = type; }
+
+ // Returns the scan result type.
+ ResultType result_type() const { return result_type_; }
+ void set_result_type(ResultType type) { result_type_ = type; }
+
+ // Returns the report delay value in milliseconds.
+ const base::TimeDelta& report_delay() const { return report_delay_ms_; }
+ void set_report_delay(const base::TimeDelta& delay) {
+ report_delay_ms_ = delay;
+ }
+
+ // Returns the hardware filter match mode.
+ MatchMode match_mode() const { return match_mode_; }
+ void set_match_mode(MatchMode mode) { match_mode_ = mode; }
+
+ // Returns the count of advertisements to match per filter.
+ MatchCount match_count_per_filter() const { return match_count_per_filter_; }
+ void set_match_count_per_filter(MatchCount count) {
+ match_count_per_filter_ = count;
+ }
+
+ // Comparison operator.
+ bool operator==(const ScanSettings& rhs) const;
+
+ private:
+ Mode mode_;
+ CallbackTypeBitField callback_type_;
+ ResultType result_type_;
+ base::TimeDelta report_delay_ms_;
+ MatchMode match_mode_;
+ MatchCount match_count_per_filter_;
+};
+
+} // namespace bluetooth
diff --git a/service/common/bluetooth/uuid.cpp b/service/common/bluetooth/uuid.cpp
index e96934d..8a34437 100644
--- a/service/common/bluetooth/uuid.cpp
+++ b/service/common/bluetooth/uuid.cpp
@@ -44,6 +44,20 @@
return UUID(bytes);
}
+// static
+UUID UUID::GetNil() {
+ UUID128Bit bytes;
+ bytes.fill(0);
+ return UUID(bytes);
+}
+
+// static
+UUID UUID::GetMax() {
+ UUID128Bit bytes;
+ bytes.fill(1);
+ return UUID(bytes);
+}
+
void UUID::InitializeDefault() {
// Initialize to Bluetooth SIG base UUID.
id_ = kSigBaseUUID;
diff --git a/service/common/bluetooth/uuid.h b/service/common/bluetooth/uuid.h
index a88476f..ec89f1e 100644
--- a/service/common/bluetooth/uuid.h
+++ b/service/common/bluetooth/uuid.h
@@ -37,6 +37,12 @@
// Creates and returns a random 128-bit UUID.
static UUID GetRandom();
+ // Creates and returns a UUID in which all 128 bits are equal to 0.
+ static UUID GetNil();
+
+ // Creates and returns a UUID in which all 128 bits are equal to 1.
+ static UUID GetMax();
+
// Construct a Bluetooth 'base' UUID.
UUID();
@@ -71,6 +77,9 @@
bool operator<(const UUID& rhs) const;
bool operator==(const UUID& rhs) const;
+ inline bool operator!=(const UUID& rhs) const {
+ return !(*this == rhs);
+ }
private:
void InitializeDefault();
diff --git a/service/test/parcel_helpers_unittest.cpp b/service/test/parcel_helpers_unittest.cpp
index f79beec..138f9b5 100644
--- a/service/test/parcel_helpers_unittest.cpp
+++ b/service/test/parcel_helpers_unittest.cpp
@@ -25,6 +25,9 @@
using bluetooth::AdvertiseData;
using bluetooth::AdvertiseSettings;
using bluetooth::GattIdentifier;
+using bluetooth::ScanFilter;
+using bluetooth::ScanResult;
+using bluetooth::ScanSettings;
using bluetooth::UUID;
namespace ipc {
@@ -71,6 +74,33 @@
return id_in == *id_out;
}
+bool TestScanSettings(const ScanSettings& settings_in) {
+ Parcel parcel;
+ WriteScanSettingsToParcel(settings_in, &parcel);
+ parcel.setDataPosition(0);
+ auto settings_out = CreateScanSettingsFromParcel(parcel);
+
+ return settings_in == *settings_out;
+}
+
+bool TestScanFilter(const ScanFilter& filter_in) {
+ Parcel parcel;
+ WriteScanFilterToParcel(filter_in, &parcel);
+ parcel.setDataPosition(0);
+ auto filter_out = CreateScanFilterFromParcel(parcel);
+
+ return filter_in == *filter_out;
+}
+
+bool TestScanResult(const ScanResult& result_in) {
+ Parcel parcel;
+ WriteScanResultToParcel(result_in, &parcel);
+ parcel.setDataPosition(0);
+ auto result_out = CreateScanResultFromParcel(parcel);
+
+ return result_in == *result_out;
+}
+
TEST(ParcelHelpersTest, EmptyAdvertiseData) {
std::vector<uint8_t> data;
AdvertiseData adv(data);
@@ -131,6 +161,52 @@
TestGattIdentifier(*desc_id);
}
+TEST(ParcelHelpersTest, ScanSettings) {
+ ScanSettings settings0;
+ ScanSettings settings1(
+ ScanSettings::MODE_BALANCED,
+ ScanSettings::CALLBACK_TYPE_FIRST_MATCH,
+ ScanSettings::RESULT_TYPE_ABBREVIATED,
+ base::TimeDelta::FromMilliseconds(150),
+ ScanSettings::MATCH_MODE_STICKY,
+ ScanSettings::MATCH_COUNT_FEW_ADVERTISEMENTS);
+
+ EXPECT_TRUE(TestScanSettings(settings0));
+ EXPECT_TRUE(TestScanSettings(settings1));
+}
+
+TEST(ParcelHelpersTest, ScanFilter) {
+ ScanFilter filter;
+
+ filter.set_device_name("Test Device Name");
+ ASSERT_TRUE(filter.SetDeviceAddress("01:02:04:AB:CD:EF"));
+ EXPECT_TRUE(TestScanFilter(filter));
+
+ UUID uuid = UUID::GetRandom();
+ filter.SetServiceUuid(uuid);
+ EXPECT_TRUE(TestScanFilter(filter));
+
+ UUID mask = UUID::GetRandom();
+ filter.SetServiceUuidWithMask(uuid, mask);
+ EXPECT_TRUE(TestScanFilter(filter));
+}
+
+TEST(ParcelHelpersTest, ScanResult) {
+ const char kTestAddress[] = "01:02:03:AB:CD:EF";
+ const char kEmptyAddress[] = "";
+
+ const std::vector<uint8_t> kEmptyBytes;
+ const std::vector<uint8_t> kTestBytes{ 0x01, 0x02, 0x03 };
+
+ const int kTestRssi = 127;
+
+ ScanResult result0(kTestAddress, kEmptyBytes, kTestRssi);
+ ScanResult result1(kTestAddress, kTestBytes, kTestRssi);
+
+ EXPECT_TRUE(TestScanResult(result0));
+ EXPECT_TRUE(TestScanResult(result1));
+}
+
} // namespace
} // namespace binder
} // namespace ipc