mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-15 07:06:11 -04:00
Add battery notification and not discoverable advertisement
PiperOrigin-RevId: 532187475
This commit is contained in:
committed by
Copybara-Service
parent
0e1170c52e
commit
6d3704f50a
@@ -3,6 +3,7 @@ licenses(["notice"])
|
||||
cc_library(
|
||||
name = "common",
|
||||
srcs = [
|
||||
"battery_notification.cc",
|
||||
"fast_pair_device.cc",
|
||||
"fast_pair_http_result.cc",
|
||||
"pair_failure.cc",
|
||||
@@ -10,9 +11,11 @@ cc_library(
|
||||
],
|
||||
hdrs = [
|
||||
"account_key.h",
|
||||
"battery_notification.h",
|
||||
"constant.h",
|
||||
"fast_pair_device.h",
|
||||
"fast_pair_http_result.h",
|
||||
"non_discoverable_advertisement.h",
|
||||
"pair_failure.h",
|
||||
"protocol.h",
|
||||
],
|
||||
@@ -21,6 +24,7 @@ cc_library(
|
||||
],
|
||||
deps = [
|
||||
"//internal/crypto",
|
||||
"//internal/platform:logging",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/strings",
|
||||
@@ -36,6 +40,7 @@ cc_test(
|
||||
shard_count = 16,
|
||||
deps = [
|
||||
":common",
|
||||
"//internal/platform/implementation/g3", # build_cleaner: keep
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
@@ -51,6 +56,22 @@ cc_test(
|
||||
shard_count = 16,
|
||||
deps = [
|
||||
":common",
|
||||
"//internal/platform/implementation/g3", # build_cleaner: keep
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "battery_notification_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"battery_notification_test.cc",
|
||||
],
|
||||
shard_count = 16,
|
||||
deps = [
|
||||
":common",
|
||||
"//internal/platform/implementation/g3", # build_cleaner: keep
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 "fastpair/common/battery_notification.h"
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "fastpair/common/constant.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
BatteryInfo::BatteryInfo(bool is_charging)
|
||||
: is_charging(is_charging), percentage(std::nullopt) {}
|
||||
|
||||
BatteryInfo::BatteryInfo(bool is_charging, int8_t percentage)
|
||||
: is_charging(is_charging), percentage(percentage) {}
|
||||
|
||||
// static
|
||||
BatteryInfo BatteryInfo::FromByte(uint8_t byte) {
|
||||
// Battery value is in the form 0bSVVVVVVV.
|
||||
// S = charging (0b1) or not (0b0).
|
||||
// V = value, Ranges from 0-100, or 0bS1111111 if unknown.
|
||||
bool is_charging = byte & kBatteryChargingMask;
|
||||
uint8_t percentage = byte & kBatteryPercentageMask;
|
||||
int8_t percentage_signed = static_cast<int8_t>(percentage);
|
||||
if (percentage_signed < 0 || percentage_signed > 100) {
|
||||
NEARBY_LOGS(INFO) << __func__ << "Invalid battery percentage.";
|
||||
return BatteryInfo(is_charging);
|
||||
}
|
||||
return BatteryInfo(is_charging, percentage_signed);
|
||||
}
|
||||
|
||||
uint8_t BatteryInfo::ToByte() const {
|
||||
// Battery value is in the form 0bSVVVVVVV.
|
||||
// S = charging (0b1) or not (0b0).
|
||||
// V = value, Ranges from 0-100, or 1111111 if unknown.
|
||||
if (!percentage) {
|
||||
return is_charging ? kBatteryIsChargingByte : kBatteryNotChargingByte;
|
||||
} else {
|
||||
return percentage.value() | (is_charging ? kBatteryChargingMask : 0);
|
||||
}
|
||||
}
|
||||
|
||||
BatteryNotification::BatteryNotification(
|
||||
Type type, const std::vector<BatteryInfo>& battery_infos)
|
||||
: type(type), battery_infos(battery_infos) {}
|
||||
|
||||
// static
|
||||
std::optional<BatteryNotification> BatteryNotification::FromBytes(
|
||||
const std::vector<uint8_t>& bytes, Type type) {
|
||||
if (bytes.size() == 1) {
|
||||
// Single component device.
|
||||
NEARBY_LOGS(INFO) << __func__ << " : Single component device.";
|
||||
std::vector<BatteryInfo> battery_infos = {BatteryInfo::FromByte(bytes[0])};
|
||||
return std::make_optional<BatteryNotification>(type, battery_infos);
|
||||
} else if (bytes.size() == 3) {
|
||||
// True wireless headset expecting 3 bytes - Left bud, Right bud and case.
|
||||
NEARBY_LOGS(INFO) << __func__ << " : True wireless headset.";
|
||||
std::vector<BatteryInfo> battery_infos = {
|
||||
/* left bud info */ BatteryInfo::FromByte(bytes[0]),
|
||||
/* right bud info */ BatteryInfo::FromByte(bytes[1]),
|
||||
/* case info */ BatteryInfo::FromByte(bytes[2])};
|
||||
return std::make_optional<BatteryNotification>(type, battery_infos);
|
||||
}
|
||||
NEARBY_LOGS(WARNING) << __func__
|
||||
<< " : Unexpected battery notification length :"
|
||||
<< bytes.size();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_BATTERY_NOTIFICATION_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_BATTERY_NOTIFICATION_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
// Fast Pair battery information from notification. See
|
||||
// https://developers.google.com/nearby/fast-pair/spec#BatteryNotification
|
||||
struct BatteryInfo {
|
||||
BatteryInfo() = default;
|
||||
explicit BatteryInfo(bool is_charging);
|
||||
BatteryInfo(bool is_charging, int8_t percentage);
|
||||
~BatteryInfo() = default;
|
||||
|
||||
static BatteryInfo FromByte(uint8_t byte);
|
||||
|
||||
uint8_t ToByte() const;
|
||||
|
||||
bool is_charging = false;
|
||||
std::optional<int8_t> percentage;
|
||||
};
|
||||
|
||||
// Fast Pair battery notification. See
|
||||
// https://developers.google.com/nearby/fast-pair/spec#BatteryNotification
|
||||
struct BatteryNotification {
|
||||
// Represents if the provider wants to show an indication
|
||||
// of the battery values
|
||||
enum class Type {
|
||||
kNone = 0,
|
||||
kShowUi = 3, /* Show UI indication: 0b0011 */
|
||||
kHideUi = 4, /* Hide UI indication: 0b0100 */
|
||||
};
|
||||
|
||||
BatteryNotification() = default;
|
||||
BatteryNotification(Type type, const std::vector<BatteryInfo>& battery_infos);
|
||||
~BatteryNotification() = default;
|
||||
|
||||
static std::optional<BatteryNotification> FromBytes(
|
||||
const std::vector<uint8_t>& bytes, Type type);
|
||||
|
||||
Type type = Type::kNone;
|
||||
std::vector<BatteryInfo> battery_infos;
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_BATTERY_NOTIFICATION_H_
|
||||
@@ -0,0 +1,152 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 "fastpair/common/battery_notification.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
namespace {
|
||||
// Test data comes from:
|
||||
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
|
||||
|
||||
TEST(BatteryNotificationTest, TestBatteryInfo) {
|
||||
// Tests default constructor
|
||||
BatteryInfo battery_info_1;
|
||||
EXPECT_FALSE(battery_info_1.is_charging);
|
||||
|
||||
// Tests Constructor with is_charging
|
||||
BatteryInfo battery_info_2(true);
|
||||
EXPECT_TRUE(battery_info_2.is_charging);
|
||||
// Tests ToByte and FromByte
|
||||
BatteryInfo battery_info_3 = BatteryInfo::FromByte(battery_info_2.ToByte());
|
||||
EXPECT_TRUE(battery_info_3.is_charging);
|
||||
EXPECT_FALSE(battery_info_3.percentage.has_value());
|
||||
|
||||
// Tests Constructor with is_charging and percentage value
|
||||
BatteryInfo battery_info_4(true, 80);
|
||||
EXPECT_TRUE(battery_info_4.is_charging);
|
||||
EXPECT_EQ(battery_info_4.percentage.value(), 80);
|
||||
// Tests ToByte and FromByte
|
||||
BatteryInfo battery_info_5 = BatteryInfo::FromByte(battery_info_4.ToByte());
|
||||
EXPECT_TRUE(battery_info_5.is_charging);
|
||||
EXPECT_EQ(battery_info_5.percentage.value(), 80);
|
||||
|
||||
// Tests Constructor with is_charging and wrong percentage value
|
||||
BatteryInfo battery_info_6(true, 110);
|
||||
// Tests ToByte and FromByte
|
||||
BatteryInfo battery_info_7 = BatteryInfo::FromByte(battery_info_6.ToByte());
|
||||
EXPECT_TRUE(battery_info_7.is_charging);
|
||||
EXPECT_FALSE(battery_info_7.percentage.has_value());
|
||||
|
||||
// Tests FromByte with battery percentage = 0
|
||||
BatteryInfo battery_info_8 = BatteryInfo::FromByte(0);
|
||||
EXPECT_FALSE(battery_info_8.is_charging);
|
||||
EXPECT_EQ(battery_info_8.percentage.value(), 0);
|
||||
|
||||
BatteryInfo battery_info_10 = BatteryInfo::FromByte(0x80);
|
||||
EXPECT_TRUE(battery_info_10.is_charging);
|
||||
EXPECT_EQ(battery_info_10.percentage.value(), 0);
|
||||
|
||||
// Tests FromByte with battery percentage = 100
|
||||
BatteryInfo battery_info_9 = BatteryInfo::FromByte(100);
|
||||
EXPECT_FALSE(battery_info_9.is_charging);
|
||||
EXPECT_EQ(battery_info_9.percentage.value(), 100);
|
||||
|
||||
BatteryInfo battery_info_11 = BatteryInfo::FromByte(0x80 | 100);
|
||||
EXPECT_TRUE(battery_info_11.is_charging);
|
||||
EXPECT_EQ(battery_info_11.percentage.value(), 100);
|
||||
|
||||
// Test battery with invalid battery percentage
|
||||
BatteryInfo battery_info_12 = BatteryInfo::FromByte(0x7F);
|
||||
EXPECT_FALSE(battery_info_12.is_charging);
|
||||
EXPECT_FALSE(battery_info_12.percentage.has_value());
|
||||
|
||||
BatteryInfo battery_info_13 = BatteryInfo::FromByte(0xFF);
|
||||
EXPECT_TRUE(battery_info_13.is_charging);
|
||||
EXPECT_FALSE(battery_info_13.percentage.has_value());
|
||||
}
|
||||
|
||||
TEST(BatteryNotificationTest, TestBatteryNotificationDefaultConstructor) {
|
||||
// Tests default constructor
|
||||
BatteryNotification battery_notification;
|
||||
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kNone);
|
||||
EXPECT_EQ(battery_notification.battery_infos.size(), 0);
|
||||
}
|
||||
|
||||
TEST(BatteryNotificationTest, TestBatteryNotificationForSingleComponentDevice) {
|
||||
std::vector<BatteryInfo> battery_infos = {BatteryInfo(false, 70)};
|
||||
BatteryNotification battery_notification(BatteryNotification::Type::kShowUi,
|
||||
battery_infos);
|
||||
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kShowUi);
|
||||
EXPECT_FALSE(battery_notification.battery_infos.at(0).is_charging);
|
||||
EXPECT_EQ(battery_notification.battery_infos.at(0).percentage.value(), 70);
|
||||
}
|
||||
|
||||
TEST(BatteryNotificationTest, TestBatteryNotificationForTrueWirelessHeadset) {
|
||||
std::vector<BatteryInfo> battery_infos = {
|
||||
BatteryInfo(false, 70), BatteryInfo(false, 80), BatteryInfo(true, 90)};
|
||||
BatteryNotification battery_notification(BatteryNotification::Type::kShowUi,
|
||||
battery_infos);
|
||||
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kShowUi);
|
||||
// Left bud
|
||||
EXPECT_FALSE(battery_notification.battery_infos.at(0).is_charging);
|
||||
EXPECT_EQ(battery_notification.battery_infos.at(0).percentage.value(), 70);
|
||||
// Right bud
|
||||
EXPECT_FALSE(battery_notification.battery_infos.at(1).is_charging);
|
||||
EXPECT_EQ(battery_notification.battery_infos.at(1).percentage.value(), 80);
|
||||
// Case
|
||||
EXPECT_TRUE(battery_notification.battery_infos.at(2).is_charging);
|
||||
EXPECT_EQ(battery_notification.battery_infos.at(2).percentage.value(), 90);
|
||||
}
|
||||
|
||||
TEST(BatteryNotificationTest,
|
||||
TestBatteryNotificationFromBytesForSingleComponentDevice) {
|
||||
const std::vector<uint8_t> batteryData{0b01000000};
|
||||
BatteryNotification battery_notification =
|
||||
BatteryNotification::FromBytes(batteryData,
|
||||
BatteryNotification::Type::kShowUi)
|
||||
.value();
|
||||
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kShowUi);
|
||||
EXPECT_EQ(battery_notification.battery_infos.at(0).percentage.value(), 64);
|
||||
}
|
||||
|
||||
TEST(BatteryNotificationTest,
|
||||
TestBatteryNotificationFromBytesForTrueWirelessHeadset) {
|
||||
const std::vector<uint8_t> batteryData{0b01000000, 0b01000000, 0b01000000};
|
||||
BatteryNotification battery_notification =
|
||||
BatteryNotification::FromBytes(batteryData,
|
||||
BatteryNotification::Type::kShowUi)
|
||||
.value();
|
||||
EXPECT_EQ(battery_notification.type, BatteryNotification::Type::kShowUi);
|
||||
EXPECT_EQ(battery_notification.battery_infos.at(0).percentage.value(), 64);
|
||||
EXPECT_EQ(battery_notification.battery_infos.at(1).percentage.value(), 64);
|
||||
EXPECT_EQ(battery_notification.battery_infos.at(2).percentage.value(), 64);
|
||||
}
|
||||
|
||||
TEST(BatteryNotificationTest, TestBatteryNotificationFromWrongBytes) {
|
||||
const std::vector<uint8_t> batteryDataWithWrongLenth{0b01000000, 0b01000000};
|
||||
EXPECT_FALSE(
|
||||
BatteryNotification::FromBytes(batteryDataWithWrongLenth,
|
||||
BatteryNotification::Type::kShowUi)
|
||||
.has_value());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -24,7 +24,6 @@ namespace fastpair {
|
||||
constexpr char kServiceId[] = "Fast Pair";
|
||||
|
||||
constexpr char kRfcommUuid[] = "df21fe2c-2515-4fdb-8886-f12c4d67927c";
|
||||
|
||||
constexpr int kAccountKeySize = 16;
|
||||
|
||||
// Key pair
|
||||
@@ -60,6 +59,13 @@ constexpr uint8_t kAccountKeyStartByte = 0x04;
|
||||
constexpr uint8_t kKeyBasedPairingType = 0x00;
|
||||
constexpr uint8_t kInitialOrSubsequentFlags = 0x00;
|
||||
constexpr uint8_t kRetroactiveFlags = 0x10;
|
||||
|
||||
// Battery Info
|
||||
constexpr int kBatteryChargingMask = 0b10000000;
|
||||
constexpr int kBatteryPercentageMask = 0b01111111;
|
||||
constexpr int kBatteryIsChargingByte = 0b11111111;
|
||||
constexpr int kBatteryNotChargingByte = 0b01111111;
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_NON_DISCOVERABLE_ADVERTISEMENT_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_NON_DISCOVERABLE_ADVERTISEMENT_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "fastpair/common/battery_notification.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
// Fast Pair 'Not Discoverable' advertisement. See
|
||||
// https://developers.google.com/nearby/fast-pair/specifications/service/provider#AdvertisingWhenNotDiscoverable
|
||||
struct NonDiscoverableAdvertisement {
|
||||
// Represents showing UI indication
|
||||
enum class Type {
|
||||
kShowUi = 0, /* Show UI indication: 0b0000*/
|
||||
kNone = 1,
|
||||
kHideUi = 2, /* Hide UI indication: 0b0010*/
|
||||
};
|
||||
|
||||
NonDiscoverableAdvertisement() = default;
|
||||
NonDiscoverableAdvertisement(
|
||||
std::vector<uint8_t> account_key_filter, Type type,
|
||||
std::vector<uint8_t> salt,
|
||||
std::optional<BatteryNotification> battery_notification)
|
||||
: account_key_filter(std::move(account_key_filter)),
|
||||
type(type),
|
||||
salt(std::move(salt)),
|
||||
battery_notification(std::move(battery_notification)) {}
|
||||
|
||||
~NonDiscoverableAdvertisement() = default;
|
||||
|
||||
std::vector<uint8_t> account_key_filter;
|
||||
Type type = Type::kNone;
|
||||
std::vector<uint8_t> salt;
|
||||
std::optional<BatteryNotification> battery_notification;
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_COMMON_NON_DISCOVERABLE_ADVERTISEMENT_H_
|
||||
Reference in New Issue
Block a user