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